automapper, procedura sql- nietypowa sytuacja

0

Cześć,
Mam pewien problem jak rozwiązać pewien problem z join w moim zapytaniu a mianowicie potrzebuje pewną rzecz wyciągnąć jeszcze z bazy :

class Car{
int Id; 
string CarName;
....
....
int OwnerId;
}

class CarDto{
int Id; 
string CarName
... 
...
int OwnerId;
string PersonExtraInformation; 
}

Aby uzupełnić PersonExtraInformation muszę sięgnac do funkcji w sql GetPersonInformation.

using (db= new MyDbContext()){
 var model = db.Car.ProjectTo<CarDto>();  //uzupelniamy cały CarDto oprócz PersonExtraInformation
}

I jak teraz uzupelnić to pole korzystajac z funkcji tabelarycznej ? próbuje coś takiego ale czy to dobry pomysł ???

using (db= new MyDbContext()){
 var carDto= db.Car.ProjectTo<CarDto>();  //uzupelniamy cały CarDto oprócz PersonExtraInformation

var result = (
from dto in carDto
join pei in db.PersonExtraInformation on dto.OwnerId equals pei .PersonId
select new CarDto(dto ){PersonExtraInformation = pei.PersonExtraInformation }
).ToList();
}

Minusem tego rozwiazania jest ze dwukrotnie wystepuje mapowanie prawie calego obiektu, najpierw z Car na CarDTO a pozniej CarDTO na CarDTO. Czy da sie to zrobic lepiej ?

0

To nie wyciągaj dwukrotnie tego samego obiektu, wyrzuć carDto = db.Car.ProjectTo<CarDto>(); i użyj tylko drugiego zapytania.
Ale czy jesteś pewien, że select new CarDto(dto) zadziała? To nie jest mapowanie obiektów, tylko generowanie sql, jak EF ma wygenerować sql, w którym wykona się new CarDto(dto)? Uruchamiałeś to? Jeśli zadziała, to oznacza to, że jest to etap mapowania obiektów, czyli dane do joina muszą być wyciągnięte z bazy danych przed joinem (wtedy ściągana jest cała tabela!) albo w trakcie (wtedy masz setki drobnych zapytań).

Możesz dodać view albo sp, które zwróci zawartość tabeli Car wraz z dołączonym polem PersonExtraInformation z powiązanej tabeli, lub tak jak napisał poniżej @Juhas - moim zdaniem najlepsze rozwiązanie - całość Car + PersonExtraInformation zaciągnąć w jednym zapytaniu linq.

Mam jeszcze wątpliwości co do var carDto = db.Car.ProjectTo<CarDto>(). Co, jeśli będziesz mieć tu kilkaset tysięcy rekordów, albo nawet tylko kilkadziesiąt tysięcy? Zawsze wyświetlasz użytkownikowi wszystkie rekordy? Czy też zawsze przetwarzasz te rekordy naraz?

0

Myślę, że powinieneś tu mieć coś innego do odczytu i do zapisu danych. Tzn. zapis robisz tak, jak do tej pory. A odczyt - musisz stworzyć nowy model, np:

class FullCarDto: CarDto
{
    public string PersonInformation {get;set;}
}

Coś w ten deseń pokombinuj.
Ewentualnie możesz cały CarDTO pociągnąć raz za pomocą LINQ. I tylko LINQ.

0
ŁF napisał(a):

To nie wyciągaj dwukrotnie tego samego obiektu, wyrzuć carDto = db.Car.ProjectTo<CarDto>(); i użyj tylko drugiego zapytania.
Ale czy jesteś pewien, że select new CarDto(dto) zadziała? To nie jest mapowanie obiektów, tylko generowanie sql, jak EF ma wygenerować sql, w którym wykona się new CarDto(dto)? Uruchamiałeś to? Jeśli zadziała, to oznacza to, że jest to etap mapowania obiektów, czyli dane do joina muszą być wyciągnięte z bazy danych przed joinem (wtedy ściągana jest cała tabela!) albo w trakcie (wtedy masz setki drobnych zapytań).

Możesz dodać view albo sp, które zwróci zawartość tabeli Car wraz z dołączonym polem PersonExtraInformation z powiązanej tabeli, lub tak jak napisał poniżej @Juhas - moim zdaniem najlepsze rozwiązanie - całość Car + PersonExtraInformation zaciągnąć w jednym zapytaniu linq.

Mam jeszcze wątpliwości co do var carDto = db.Car.ProjectTo<CarDto>(). Co, jeśli będziesz mieć tu kilkaset tysięcy rekordów, albo nawet tylko kilkadziesiąt tysięcy? Zawsze wyświetlasz użytkownikowi wszystkie rekordy? Czy też zawsze przetwarzasz te rekordy naraz?

Niestety muszę uniknąć dodawania czegoś do bazy czyli odpada wersja z dodaniem View lub sp.
Faktycznie linijka select new CarDto(dto ) ..... tworzy kolejne problemy :/
niby znalazłem obejście ale też nie powala a mianowicie wygląda tak :

using (db= new MyDbContext()){
 var model = db.Car.ProjectTo<CarDto>();  //uzupelniamy cały CarDto oprócz PersonExtraInformation

var dic = (
 from m in model.select(s=>s.OwnerId).distinct()
join pi in GetPersonInformation() on m equals pi.PersonId
select new {m.Value, pi. PersonExtraInformation}
).asEnumerable()

foreach(var item in dictionary)
{
model.where(s=>s.OwnerId==item.Value).ForEach(s=>s.PersonExtraInformation = item.PersonExtraInformation);
}
}

No ale niestety wymaga to dwukrotnego uderzenia do bazy a później "dopasowania" co też jest słabym rozwiązaniem

0
ice25 napisał(a):

Faktycznie linijka select new CarDto(dto ) ..... tworzy kolejne problemy :/

Czy tworzy problemy oznacza, że wywala jakiś błąd? Której wersji EF używasz? Umieram z ciekawości :)

0

.Where() na IEnumerable i tak spowoduje przeiterowanie po wszystkich danych. Zresztą samo złączenie z danymi z pamięci spowoduje wygenerowanie IQueryable<T> opartego pod spodem o linq-to-object, a nie linq-to-sql. Pytanie tylko, czy będziesz mieć setki drobnych zapytań o PersonExtraInformation, czy jedno duże.
Tak czy inaczej ogarnij profiler do sql i zobacz co idzie do bazy danychj.

1 użytkowników online, w tym zalogowanych: 0, gości: 1