2009-05-18 16 views
77

Dlaczego pojawia się błąd:Entity Framework - „Nie można utworzyć stałą wartość typu«typu zamknięcie»...” błąd

Unable to create a constant value of type 'Closure type'. Only primitive types (for instance Int32, String and Guid) are supported in this context.

Kiedy próbuję wyliczyć następujące kwerendy Linq?

IEnumerable<string> searchList = GetSearchList(); 
using (HREntities entities = new HREntities()) 
{ 
    var myList = from person in entities.vSearchPeople 
    where upperSearchList.All((person.FirstName + person.LastName) .Contains).ToList(); 
} 

Aktualizacja: Gdybym spróbuj następujących po prostu spróbować, aby wyizolować problem, otrzymuję ten sam błąd:

where upperSearchList.All(arg => arg == arg) 

Wygląda więc na to, że problem jest ze wszystkich metod, dobrze? Jakieś sugestie?

Odpowiedz

67

Wygląda na to, że próbujesz wykonać odpowiednik warunku "GDZIE ... W". Sprawdź numer How to write 'WHERE IN' style queries using LINQ to Entities, aby dowiedzieć się, jak wykonać tego typu zapytanie za pomocą LINQ do jednostek.

Sądzę, że komunikat o błędzie jest w tym przypadku szczególnie niepomocny, ponieważ po .Contains nie występuje nawias, co powoduje, że kompilator rozpoznaje cały predykat jako wyrażenie lambda.

+0

Dzięki Daniel. Ta sama składnia działa dobrze na zwykłym Linq. Wygląda na to, że problem tkwi w EF w .Net 3.5 SP1, prawda? Zawartość bez nawiasu jest równoważna z: gdzie upperSearchList.All (x => (person.FirstName + person.LastName) .Contains (x)). ToList(); –

+0

Jeśli spróbuję gdzie upperSearchList.All (arg => arg == arg), zgłasza ten sam błąd. Problem z metodą All ... –

+2

LINQ to Entities to wspaniała technologia, ale silnik do tłumaczenia SQL jest ograniczony. Nie mogę położyć ręki na oficjalnej dokumentacji, ale z mojego doświadczenia wynika, że ​​jeśli zapytanie zawiera więcej niż tylko podstawowe funkcje matematyczne i łańcuchowe/daty, to nie zadziała. Czy miałeś okazję sprawdzić, który post został połączony? Opisuje proces konwertowania zapytania typu "WHERE..IN" do postaci, którą LINQ do Entities można następnie przetłumaczyć na SQL. –

11

Spędziłem ostatnie 6 miesięcy walcząc z tym ograniczeniem z EF 3.5 i chociaż nie jestem najmądrzejszą osobą na świecie, jestem prawie pewien, że mam coś przydatnego do zaoferowania na ten temat.

SQL wygenerowany przez wyrośnięcie drzewa o wysokości 50 mil wyrażenia "OR style" spowoduje słaby plan wykonania kwerendy. Mam do czynienia z kilkoma milionami wierszy, a wpływ jest znaczny.

Jest trochę Hack znalazłem zrobić SQL „w”, który pomaga, jeśli tylko szukasz grono podmiotów przez ID:

private IEnumerable<Entity1> getByIds(IEnumerable<int> ids) 
{ 
    string idList = string.Join(",", ids.ToList().ConvertAll<string>(id => id.ToString()).ToArray()); 
    return dbContext.Entity1.Where("it.pkIDColumn IN {" + idList + "}"); 
} 

gdzie pkIDColumn jest podstawowy klucz nazwa kolumny id Twój stół Entity1.

ALE PRZECZYTAJ CZYTANIE!

To jest w porządku, ale wymaga to posiadania identyfikatorów tego, co muszę znaleźć. Czasami po prostu chcę, by moje wyrażenia sięgały do ​​innych relacji, a to, co mam, to kryteria dla tych powiązanych relacji.

Gdybym miał więcej czasu, spróbowałbym przedstawić to wizualnie, ale nie zastanawiam się przez chwilę nad tym zdaniem: Zastanów się nad schematem za pomocą tabel Person, GovernmentId i GovernmentIdType. Andrew Tappert (osoba) ma dwie karty id (GovernmentId), jedną z Oregon (GovernmentIdType) i jedną z Washington (GovernmentIdType).

Teraz wygeneruj edmx z niego.

Teraz wyobraź sobie, że chcesz znaleźć wszystkie osoby posiadające pewną wartość identyfikatora, powiedzmy 1234567.

Można to osiągnąć z jednej bazy danych uderzony z tym:

dbContext context = new dbContext(); 
string idValue = "1234567"; 
Expression<Func<Person,bool>> expr = 
    person => person.GovernmentID.Any(gid => gid.gi_value.Contains(idValue)); 

IEnumerable<Person> people = context.Person.AsQueryable().Where(expr); 

widzisz podzapytanie tutaj? Wygenerowany sql użyje "sprzężeń" zamiast pod-zapytań, ale efekt jest taki sam. Obecnie serwer SQL optymalizuje podkwerendy do złączeń pod pokrywami, ale tak czy inaczej ...

Kluczem do tego działania jest. Any wewnątrz wyrażenia.

0

Mam ten komunikat o błędzie, gdy mój obiekt tablica używana w funkcji .Wszystkie jest null Po zainicjowaniu obiektu Array, (upperSearchList w Twoim przypadku), błąd zniknął Komunikat o błędzie mylące w tym przypadku

gdzie upperSearchList.All (arg => person.someproperty.StartsWith (Arg)))

8

znalazłem przyczynę błędu (Używam Framework 4.5). Problem polega na tym, że EF typu złożonego, który jest przekazywany w parametrze "Zawiera", nie może być przetłumaczony na zapytanie SQL. EF można używać w zapytaniu SQL tylko prostych typów, takich jak int, string ...

this.GetAll().Where(p => !assignedFunctions.Contains(p)) 

GETALL zawiera listę obiektów o złożonej typu (na przykład: „Function”). Tak więc, spróbuję tutaj, aby otrzymać wystąpienie tego złożonego typu w moim zapytaniu SQL, które oczywiście nie może działać!

Jeśli mogę wydobyć z mojej listy, parametry, które są dostosowane do moich poszukiwań, mogę użyć:

var idList = assignedFunctions.Select(f => f.FunctionId); 
this.GetAll().Where(p => !idList.Contains(p.FunktionId)) 

Teraz EF nie ma typu złożonego „funkcja” do pracy, ale np prosta typ (długi). I to działa dobrze!

Powiązane problemy