[LINQ] Zapytaniem Linq To Entities (mapowanie sql na własne modele VS)

0

Witam,

Mam problem z zapytaniem linq, które mapuje dane z bazy na moje klasy, co w nim może być nie tak?

Wyświetlany komunikat

 
Składnik LINQ to Entities nie może rozpoznać metody „System.Collections.Generic.List`1[FakturyEdi.Models.PozycjaViewModel] ToList[PozycjaViewModel](System.Collections.Generic.IEnumerable`1[FakturyEdi.Models.PozycjaViewModel])” i nie można przetłumaczyć jej na wyrażenie magazynu.

kod źródlowy

        public ZamowienieViewModel GetZamowienieById(int id)
        {
            using (var db = _context.CreateNew())
            {
                var query = db.Zamowienia
                    .Where(x => x.ZamowienieID == id)
                    .Select(x => new ZamowienieViewModel
                    {
                        ZamowienieId = x.ZamowienieID,
                        NrZamowienia = x.NrZamowienia,
                        DataSprzedazy = x.DataSprzedazy,
                        DataZamowienia = x.DataZamowienia,
                        Faktura = new FakturaViewModel
                        {
                            FakturaId = x.Faktury.FakturaID,
                            NrFaktury = x.Faktury.NrFaktury,
                            Nip = x.Faktury.Nip,
                            DataWystawienia = x.Faktury.DataWystawienia,
                            TerminZaplaty = x.Faktury.TerminZaplaty,
                            Adres = new AdresViewModel
                            {
                                AdresId = x.Faktury.Adres.AdresID,
                                Imie = x.Faktury.Adres.Imie,
                                Nazwisko = x.Faktury.Adres.Nazwisko,
                                Ulica = x.Faktury.Adres.Ulica,
                                NrDomu = x.Faktury.Adres.NrDomu,
                                KodPocztowy = x.Faktury.Adres.KodPocztowy,
                                Miasto = x.Faktury.Adres.Miasto,
                                Kraj = x.Faktury.Adres.Kraj
                            }
                        },
                        Klient = new KlientViewModel
                        {
                            KlientId = x.Klienci.KlientID,
                            NrKlienta = x.Klienci.NrKlienta,
                            Nip = x.Klienci.Nip,
                            Adres = new AdresViewModel
                            {
                                AdresId = x.Klienci.Adres.AdresID,
                                Imie = x.Klienci.Adres.Imie,
                                Nazwisko = x.Klienci.Adres.Nazwisko,
                                Ulica = x.Klienci.Adres.Ulica,
                                NrDomu = x.Klienci.Adres.NrDomu,
                                KodPocztowy = x.Klienci.Adres.KodPocztowy,
                                Miasto = x.Klienci.Adres.Miasto,
                                Kraj = x.Klienci.Adres.Kraj
                            }
                        },
                        Sprzedawca = new SprzedawcaViewModel
                        {
                            SprzedawcaId = x.Sprzedawcy.SprzedawcaID,
                            NrSprzedawcy = x.Sprzedawcy.NrSprzedawcy,
                            Nip = x.Sprzedawcy.Nip,
                            Adres = new AdresViewModel
                            {
                                AdresId = x.Sprzedawcy.Adres.AdresID,
                                Imie = x.Sprzedawcy.Adres.Imie,
                                Nazwisko = x.Sprzedawcy.Adres.Nazwisko,
                                Ulica = x.Sprzedawcy.Adres.Ulica,
                                NrDomu = x.Sprzedawcy.Adres.NrDomu,
                                KodPocztowy = x.Sprzedawcy.Adres.KodPocztowy,
                                Miasto = x.Sprzedawcy.Adres.Miasto,
                                Kraj = x.Sprzedawcy.Adres.Kraj
                            }
                        },
                        Pozycje = x.PozycjeZamowienia.Select(y => new PozycjaViewModel //gdzieś tutaj jest problem
                                   //bróbowałem także db.PozycjeZamowienia.Where(z => z.ZamowienieID == x.ZamowienieID).Select(y => new PozycjaViewModel
                        {
                            PozycjaId = y.PozycjaID,
                            Ilosc = y.Ilosc,
                            CenaBrutto = y.CenaBrutto,
                            DataDostawy = y.DataDostawy,
                            Rabat = y.Rabat,
                            Produkt = new ProduktViewModel
                            {
                                ProduktId = y.Produkty.ProduktID,
                                Nazwa = y.Produkty.Nazwa,
                                Vat = y.Produkty.Vat,
                                CenaNetto = y.Produkty.CenaNetto,
                                Opis = y.Produkty.Opis,
                                Dostawca = new DostawcaViewModel
                                {
                                    DostawcaId = y.Produkty.Dostawcy.DostawcaID,
                                    NrDostawcy = y.Produkty.Dostawcy.NrDostawcy,
                                    Nip = y.Produkty.Dostawcy.Nip,
                                    Adres = new AdresViewModel
                                    {
                                        AdresId = y.Produkty.Dostawcy.Adres.AdresID,
                                        Imie = y.Produkty.Dostawcy.Adres.Imie,
                                        Nazwisko = y.Produkty.Dostawcy.Adres.Nazwisko,
                                        Ulica = y.Produkty.Dostawcy.Adres.Ulica,
                                        NrDomu = y.Produkty.Dostawcy.Adres.NrDomu,
                                        KodPocztowy = y.Produkty.Dostawcy.Adres.KodPocztowy,
                                        Miasto = y.Produkty.Dostawcy.Adres.Miasto,
                                        Kraj = y.Produkty.Dostawcy.Adres.Kraj
                                    }
                                }
                            }
                        }).ToList()
                    }).SingleOrDefault();

                return query;
            }
        }

Drugi problem jest taki że nie potrafię obsłużyć sytuacji gdy wartość pola wynosi null, w jaki sposób to zrobić inaczej?
Aktualnie mam tak.

                         Faktura = x.FakturaID == null ? null : new FakturaViewModel
                        {
                            FakturaId = x.Faktury.FakturaID,
                            NrFaktury = x.Faktury.NrFaktury,
                            Nip = x.Faktury.Nip,
                            DataWystawienia = x.Faktury.DataWystawienia,
                            TerminZaplaty = x.Faktury.TerminZaplaty,
                            Adres = new AdresViewModel
                            {
                                AdresId = x.Faktury.Adres.AdresID,
                                Imie = x.Faktury.Adres.Imie,
                                Nazwisko = x.Faktury.Adres.Nazwisko,
                                Ulica = x.Faktury.Adres.Ulica,
                                NrDomu = x.Faktury.Adres.NrDomu,
                                KodPocztowy = x.Faktury.Adres.KodPocztowy,
                                Miasto = x.Faktury.Adres.Miasto,
                                Kraj = x.Faktury.Adres.Kraj
                            }
                        },

Być może źle mapuje dane, komplikując to takim wielkim zapytaniem LINQ, zam wymyśliłem taki sobie sposób.
Może jest lepszy sposób na zrobienie tego?

1

Po pierwsze podziel ten kod na metody, bo takiego tasiemca nie da się czytać.
Po drugie odinstaluj polski pakiet językowy od .NET, bo takiego komunikatu o błędzie nie da się czytać.

0

No tak ale właśnie problem w tym że jak korzystałem z metod wewnątrz LINQ otrzymywałem błąd że nie wolno zagnieżdżać metod w zapytaniu. Może ja coś robię źle? Czy to jest normalny komunikat?

0
pawel321100 napisał(a):

No tak ale właśnie problem w tym że jak korzystałem z metod wewnątrz LINQ otrzymywałem błąd że nie wolno zagnieżdżać metod w zapytaniu. Może ja coś robię źle? Czy to jest normalny komunikat?

Racja, to przecież Linq to Entities, więc metody nie wstawisz. :/

Czemu pobierasz tak skomplikowany graf obiektów od razu? Nie wyświetlisz chyba tego użytkownikowi w całości?
Czym różnią się Twoje ViewModele od Encji, że wszystko od razu projektujesz na ViewModele?

1

nie używałem nigdy linq to entities więc nie znam się a wypowiem się

ToList to funkcja która działa natychmiast - pozostałe typu Where, Select itp to metody z opóźnionym zapłonem i z tego co widzę w zapytaniu możesz używać tylko takich

W związku z tym musisz wywalić ToList a element Pozycje musi być typu IEnumerable<PozycjaViewModel> zamiast List<PozycjaViewModel> co pozwoli na leniwe doczytanie w locie (enumerator zostanie stworzony w locie kiedy zaczniesz pytać o elementy kolekcji)

0

Hm, w sumie masz racje nie potrzebne mi tyle informacji jednak to taki projekt doświadczalny. Ale rozumiem ogólna struktura mojego kodu jest ok? Jedynie w linq to entities nie wolno używać metod? Mam nadzieje że w przyszłości to zmienią ;/ Nie można nawet głupiej wartości null sprawdzić ;/

1

niczego w przyszłości nie zmienią bo to jest powiązane ze sposobem w jaki to działa i po prostu nie da się inaczej

możesz sobie robić z danymi co zechcesz tylko już po pobraniu ich do normalnych obiektów, po odpaleniu zapytania

ogólna struktura kodu nie jest ok bo nie tłumaczy czemu nie korzystasz bezpośrednio z encji tylko je przepisujesz
a nawet jeśli musisz to można to zrobić z pewnością ładniej używając jakiejś magicznej biblioteki

0

ok dzięki wielkie, nie korzystam bezpośrednio z encji ponieważ chciałem podzielić aplikacje tak aby mogła korzystać z wielu dostawców danych a korzystanie bezpośrednio z encji uniemożliwia mi to. Co do bibliotek dzięki za podpowiedź nie wiem czemu sam nie pomyślałem, zaczynam już jakichś szukać ;)

1
jawka7 napisał(a):

Ale rozumiem ogólna struktura mojego kodu jest ok?

Trudno ocenić, czy struktura jest ok, skoro cel jest niejasny.

Po to jest coś takiego jak lazy loading, żeby nie pobierać wielkich grafów obiektów na raz. Nie przypominam sobie, abym kiedykolwiek pobierał więcej niż obiekt z jedną jego podkolekcją, bo więcej danych nie da się pokazać użytkownikowi.
Takie skomplikowane zestawy danych mogą wystąpić tylko przy raportach, ale do raportowania używa się innych narzędzi (np. Reporting Services) albo po prostu pisze się widoki po stronie bazy, bo istnieje duża szansa, że z tak dużego zapytania, LINQ to Entities wygeneruje bardzo nieładny i niewydajny kod SQL.

Jedynie w linq to entities nie wolno używać metod? Mam nadzieje że w przyszłości to zmienią ;/ Nie można nawet głupiej wartości null sprawdzić ;/

Dopóki operujesz na IQueryable, a nie IEnumerable i piszesz zapytanie do bazy, to możesz używać tych metod: http://msdn.microsoft.com/en-us/library/system.data.objects.sqlclient.sqlfunctions_methods%28v=vs.110%29.aspx

Tu nie ma żadnej magii, Twój kod C# musi zostać przetłumaczony na T-SQL, a nie da się napisać translatora dowolnego kodu C# na T-SQL, stąd to ograniczenie.

jawka7 napisał(a):

ok dzięki wielkie, nie korzystam bezpośrednio z encji ponieważ chciałem podzielić aplikacje tak aby mogła korzystać z wielu dostawców danych a korzystanie bezpośrednio z encji uniemożliwia mi to.

To znaczy, że coś masz źle. Encje powinny być niezależne od tego, czy dane trzymasz w bazie relacyjnej, obiektowej, pliku czy pamięci.

Co do bibliotek dzięki za podpowiedź nie wiem czemu sam nie pomyślałem, zaczynam już jakichś szukać ;)

Zacznij od drugiego posta w tym wątku, bo tam są wszystkie.

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