2009-05-18 5 views
77

Warum ich den Fehler:Entity Framework - „Kann nicht einen konstanten Wert vom Typ‚Schliessenart‘... erstellen“ Fehler

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

Wenn ich versuche, die folgende Linq Abfrage aufzuzählen?

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(); 
} 

aktualisieren: Wenn ich die folgend nur zu versuchen, versuchen, das Problem zu isolieren, ich die gleiche Fehlermeldung erhalten:

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

So sieht es aus wie das Problem mit der All-Methode ist, Recht? Irgendwelche Vorschläge?

Antwort

67

Es sieht so aus, als ob Sie versuchen, das Äquivalent zu einem "WHERE ... IN" -Zustand zu erreichen. Ein Beispiel für die Durchführung dieses Abfragetyps mit LINQ to Entities finden Sie unter How to write 'WHERE IN' style queries using LINQ to Entities.

Auch denke ich, die Fehlermeldung ist in diesem Fall besonders hilfreich, weil .Contains nicht von Klammern gefolgt wird, die den Compiler das gesamte Prädikat als Lambda-Ausdruck erkennt.

+0

Danke Daniel. Die gleiche Syntax funktioniert gut mit Linq. Also, es sieht nach Problem ist mit EF in. NET 3.5 SP1 richtig? Das Enthält ohne Klammern entspricht: wo obereSuchliste.Alle (x => (person.FirstName + person.LastName). Enthält (x)). ToList(); –

+0

Wenn ich versuche, wo upperSearchList.All (arg => arg == arg) es den gleichen Fehler wirft. So ist das Problem mit der All-Methode ... –

+2

LINQ to Entities ist eine wunderbare Technologie, aber die SQL-Übersetzungs-Engine ist begrenzt. Ich kann nicht die offizielle Dokumentation in die Hände bekommen, aber nach meiner Erfahrung wird es nicht funktionieren, wenn die Abfrage mehr als nur einfache Mathematik- und String/Date-Funktionen enthält. Hattest du die Chance, den Beitrag zu lesen, den ich verlinkt habe? Es beschreibt einen Prozess zum Umwandeln einer Abfrage vom Typ "WHERE..IN" in ein Formular, das LINQ to Entities dann in SQL übersetzen kann. –

11

Ich habe die letzten 6 Monate damit verbracht, diese Einschränkung mit EF 3.5 zu bekämpfen und obwohl ich nicht die klügste Person der Welt bin, bin ich ziemlich sicher, dass ich etwas Nützliches zu diesem Thema zu bieten habe.

Die SQL, die generiert wird, indem ein 50 Meilen hoher Baum von "OR-Stil" -Ausdrücken wächst, führt zu einem schlechten Abfrageausführungsplan. Ich habe es mit ein paar Millionen Zeilen zu tun und die Auswirkungen sind beträchtlich.

Es gibt einen kleinen Hack, den ich ‚in‘ eine SQL zu tun gefunden, das hilft, wenn Sie nur für eine Reihe von Einrichtungen, die von id suchen:

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 + "}"); 
} 

wo pkIDColumn ist Ihre primären Schlüssel-ID Spalt Namen Ihre Entity1-Tabelle.

ABER LESEN!

Das ist in Ordnung, aber es erfordert, dass ich bereits die IDs von dem habe, was ich finden muss. Manchmal möchte ich nur, dass meine Ausdrücke in andere Beziehungen hineinreichen und was ich habe, sind Kriterien für diese verbundenen Beziehungen.

Wenn ich mehr Zeit hätte, würde ich versuchen, dies visuell darzustellen, aber ich studiere diesen Satz nicht nur einen Moment: Betrachten Sie ein Schema mit einer Person, GovernmentId und GovernmentIdType-Tabellen. Andrew Tappert (Person) hat zwei ID-Karten (GovernmentId), eine aus Oregon (GovernmentIdType) und eine aus Washington (GovernmentIdType).

Jetzt generieren Sie eine EDMX daraus.

Nun stellen Sie alle Leute finden, wollen einen bestimmten ID-Wert, sagt 1234567.

Dies kann mit einer einzigen Datenbank mit diesem Hit erreicht werden:

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); 

Haben Sie die Unterabfrage zu sehen Hier? Das generierte sql verwendet 'Joins' anstelle von Unterabfragen, aber der Effekt ist der gleiche. Heutzutage optimiert SQL Server Unterabfragen in Joins unter den Abdeckungen sowieso, aber trotzdem ...

Der Schlüssel zu dieser Arbeit ist die .Any innerhalb des Ausdrucks.

0

bekam ich diese Fehlermeldung, wenn mein Array-Objekt in der Funktion null .Alle verwendet wird, ist Nachdem ich das Array-Objekt initialisiert, (upperSearchList in Ihrem Fall), wird der Fehler Die Fehlermeldung in diesem Fall war irreführend gegangen

wo upperSearchList.All (arg => person.someproperty.StartsWith (arg)))

8

ich die Ursache für den Fehler gefunden haben (ich bin mit Framework 4.5). Das Problem ist, dass EF, ein komplexer Typ, der im "Contains" -Parameter übergeben wird, nicht in eine SQL-Abfrage übersetzt werden kann. EF kann in einer SQL-Abfrage nur einfache Typen wie int, string ...

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

GetAll bietet eine Liste von Objekten mit einem komplexen Typ (zum Beispiel: „Funktion“) verwenden. Daher würde ich hier versuchen, eine Instanz dieses komplexen Typs in meiner SQL-Abfrage zu erhalten, was natürlich nicht funktionieren kann!

Wenn ich von meiner Liste extrahieren, Parameter, die zu meiner Suche geeignet sind, kann ich verwenden:

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

Jetzt EF nicht mehr die komplexe Typ „Funktion“ zu arbeiten, aber zum Beispiel mit einem einfachen Geben Sie (lang) ein. Und das funktioniert gut!

Verwandte Themen