Istnieje typ jednostki o nazwie produkt, który jest generowany przez strukturę encji. Napisałem to zapytanie
public IQueryable<Product> GetProducts(int categoryID)
{
return from p in db.Products
where p.CategoryID== categoryID
select new Product { Name = p.Name};
}
Poniższy kod zgłasza następujący błąd:
„Encji lub typu złożonego Shop.Product nie można zbudować w zapytaniu LINQ to Entities”
var products = productRepository.GetProducts(1).Tolist();
Ale kiedy używam select p
zamiast select new Product { Name = p.Name};
tego działa poprawnie.
Jak mogę wykonać niestandardową sekcję wyboru?
c#
entity-framework
Ghooti Farangi
źródło
źródło
Odpowiedzi:
Nie można (i nie powinno być możliwe) rzutowanie na zmapowany obiekt. Możesz jednak rzutować na anonimowy typ lub na DTO :
A twoja metoda zwróci listę DTO.
źródło
Możesz rzutować na anonimowy typ, a następnie z niego na typ modelu
Edycja : Będę bardziej szczegółowy, ponieważ to pytanie zyskało wiele uwagi.
Nie można rzutować bezpośrednio na typ modelu (ograniczenie EF), więc nie można tego obejść. Jedynym sposobem jest rzutowanie na typ anonimowy (pierwsza iteracja), a następnie na typ modelu (druga iteracja).
Należy również pamiętać, że gdy częściowe ładowanie w ten sposób jest częściowe, nie można ich aktualizować, więc powinny pozostać odłączone, ponieważ są.
Nigdy do końca nie rozumiałem, dlaczego nie jest to możliwe, a odpowiedzi w tym wątku nie dają mocnych powodów do tego (głównie mówiąc o częściowo załadowanych danych). Prawdą jest, że w stanie częściowo załadowanym nie można zaktualizować encji, ale wtedy ta encja zostanie odłączona, więc przypadkowe próby ich zapisania nie byłyby możliwe.
Zastanów się nad metodą, której użyłem powyżej: w rezultacie nadal mamy częściowo załadowany element modelu. Ten byt jest odłączony.
Rozważ ten (możliwy do istnienia) kod:
Może to również prowadzić do utworzenia listy odłączonych jednostek, więc nie musielibyśmy wykonywać dwóch iteracji. Kompilator byłby mądry, gdyby zobaczył, że użyto AsNoTracking (), co spowoduje odłączenie encji, co pozwoli nam to zrobić. Gdyby jednak pominięto AsNoTracking (), mógłby on zgłosić ten sam wyjątek, który jest teraz zgłaszany, aby ostrzec nas, że musimy być wystarczająco konkretni w kwestii oczekiwanego rezultatu.
źródło
Znalazłem inny sposób, w jaki działam, musisz zbudować klasę, która wywodzi się z klasy produktu i z niej korzystać. Na przykład:
Nie jestem pewien, czy jest to „dozwolone”, ale działa.
źródło
Oto jeden ze sposobów, aby to zrobić bez deklarowania dodatkowej klasy:
Można go jednak użyć tylko wtedy, gdy chcesz połączyć wiele jednostek w jedną całość. Powyższa funkcjonalność (proste mapowanie produktu na produkt) odbywa się w następujący sposób:
źródło
Kolejny prosty sposób :)
źródło
.ToList
zapytanie, zostanie ono wykonane i wyciągnie dane z serwera, więc po co to robić ponownieAsQueryable
?Możesz użyć tego i powinno działać -> Musisz użyć
toList
przed utworzeniem nowej listy za pomocą select:źródło
W odpowiedzi na inne pytanie oznaczone jako duplikat ( patrz tutaj ) wymyśliłem szybkie i łatwe rozwiązanie oparte na odpowiedzi Sorena:
Uwaga: To rozwiązanie działa tylko wtedy, gdy masz właściwość nawigacyjną (klucz obcy) w klasie Zadań (tutaj o nazwie „Incydent”). Jeśli tego nie masz, możesz po prostu użyć jednego z innych opublikowanych rozwiązań za pomocą „AsQueryable ()”.
źródło
Możesz rozwiązać ten problem, korzystając z obiektów przesyłania danych (DTO).
Są to trochę jak modele widokowe, w których umieszczasz potrzebne właściwości i możesz mapować je ręcznie w kontrolerze lub za pomocą rozwiązań innych firm, takich jak AutoMapper.
Z DTO możesz:
Nauczyłem się tego w szkole w tym roku i jest to bardzo przydatne narzędzie.
źródło
Jeśli używasz frameworka Entity, spróbuj usunąć właściwość z DbContext, który używa złożonego modelu, ponieważ Entity Miałem ten sam problem podczas mapowania wielu modeli na model widoku o nazwie Entity
Usunięcie wpisu z DbContext naprawiło mój błąd.
źródło
jeśli wykonujesz
Linq to Entity
, nie możesz użyćClassType
znew
przyselect
zamykaniu zapytaniaonly anonymous types are allowed (new without type)
spójrz na ten fragment mojego projektu
z dodałeś
new keyword
zamknięcie w Select nawet na tymcomplex properties
otrzymasz ten błądponieważ zostanie przekształcona w instrukcję SQL i wykonana na SqlServer
więc kiedy mogę użyć
new with types
poselect
zamknięciu?możesz go użyć, jeśli masz do czynienia
LINQ to Object (in memory collection)
po wykonaniu
ToList
na zapytanie stało sięin memory collection
to, abyśmy mogli używać gonew ClassTypes
w selectźródło
W wielu przypadkach transformacja nie jest potrzebna. Pomyśl z tego powodu, dla którego chcesz silnie wpisać List, i oceń, czy chcesz tylko dane, na przykład w serwisie internetowym lub w celu ich wyświetlenia. Nie ma znaczenia rodzaj. Musisz tylko wiedzieć, jak go odczytać i sprawdzić, czy jest identyczny z właściwościami zdefiniowanymi w zdefiniowanym typie anonimowym. To jest scenariusz optymalizacyjny, który powoduje, że nie potrzebujesz wszystkich pól encji, i dlatego istnieje typ anonimowy.
Prostym sposobem jest zrobienie tego:
źródło
Nie pozwoli Ci to odwzorować z powrotem na Produkt, ponieważ to jest twoja tabela, której szukasz. Potrzebujesz anonimowej funkcji, a następnie możesz dodać ją do ViewModel, dodać każdy ViewModel do a
List<MyViewModel>
i zwrócić je. To niewielka dygresja, ale uwzględniam zastrzeżenia dotyczące obchodzenia się z zerowymi datami, ponieważ są to problemy z tyłu, na wypadek, gdybyś miał. Tak sobie z tym poradziłem.Mam nadzieję, że masz
ProductViewModel
:Mam strukturę wstrzykiwania / repozytorium zależności, w której wywołuję funkcję w celu pobrania moich danych. Używając Twojego postu jako przykładu, w wywołaniu funkcji Kontrolera wyglądałoby to tak:
W klasie repozytorium:
Po powrocie do kontrolera wykonujesz:
źródło
dodaj tylko AsEnumerable ():
źródło
możesz dodać AsEnumerable do swojej kolekcji w następujący sposób:
źródło