2009-05-18 14 views
77

Perché ottengo l'errore:Entity Framework - "Impossibile creare un valore costante di tipo 'Tipo di chiusura' ..." Errore

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

Quando provo a enumerare la seguente query 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(); 
} 

Aggiornamento: Se provo il seguente solo per cercare di isolare il problema, ottengo lo stesso errore:

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

Quindi sembra che il problema è con il Tutto metodo, destra? Eventuali suggerimenti?

risposta

67

Sembra che tu stia cercando di fare l'equivalente di una condizione "DOVE ... IN". Controlla How to write 'WHERE IN' style queries using LINQ to Entities per un esempio di come fare quel tipo di query con LINQ alle Entità.

Inoltre, penso che il messaggio di errore non sia particolarmente utile in questo caso poiché .Contains non è seguito da parentesi, il che fa sì che il compilatore riconosca l'intero predicato come espressione lambda.

+0

Grazie Daniel. La stessa sintassi funziona bene con Linq semplice. Quindi, sembra che il problema sia con EF in .Net 3.5 SP1 giusto? Il Contains senza parentesi è equivalente a: dove upperSearchList.All (x => (person.FirstName + person.LastName) .Contains (x)). ToList(); –

+0

Se provo dove upperSearchList.All (arg => arg == arg) genera lo stesso errore. Quindi il problema è con il metodo All ... –

+2

LINQ to Entities è una tecnologia meravigliosa, ma il motore di traduzione SQL è limitato. Non riesco a mettere le mani sulla documentazione ufficiale, ma secondo la mia esperienza, se la query include più di semplici funzioni matematiche e di stringa/data, non funzionerà. Hai avuto la possibilità di controllare che post ho collegato? Descrive un processo di conversione di una query di tipo "WHERE..IN" in una forma che LINQ to Entities può quindi tradurre in SQL. –

11

Ho passato gli ultimi 6 mesi a combattere questa limitazione con EF 3.5 e mentre non sono la persona più intelligente del mondo, sono abbastanza sicuro di avere qualcosa di utile da offrire su questo argomento.

L'SQL generato dalla crescita di un albero alto 50 miglia con espressioni "OR style" si tradurrà in un piano di esecuzione delle query scadente. Ho a che fare con qualche milione di file e l'impatto è notevole.

C'è un piccolo hack che ho trovato a fare uno SQL 'in' che aiuta se sono solo alla ricerca di un gruppo di entità da 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 + "}"); 
} 

dove pkIDColumn è il tuo principale nome chiave colonna ID il tuo tavolo Entity1.

MA CONTINUI A LEGGERE!

Questo va bene, ma richiede che io abbia già gli id ​​di ciò che ho bisogno di trovare. A volte voglio solo che le mie espressioni raggiungano altre relazioni e quello che ho sono i criteri per le relazioni connesse.

Se avessi più tempo proverei a rappresentarlo visivamente, ma non lo studio solo per un momento: consideri uno schema con tabelle Persona, GovernmentId e GovernmentIdType. Andrew Tappert (Persona) ha due carte d'identità (GovernmentId), una da Oregon (GovernmentIdType) e una da Washington (GovernmentIdType).

Ora generare un edmx da esso.

Ora immaginate che si desidera trovare tutte le persone che hanno un certo valore ID, dicono 1234567.

questo può essere realizzato con un unico database colpito con questo:

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

vede il subquery Qui? Lo sql generato userà "join" invece di sottoquery, ma l'effetto è lo stesso. In questi giorni SQL server ottimizza le sottoquote in join sotto le copertine comunque, ma comunque ...

La chiave di questo funzionamento è il. Qualsiasi all'interno dell'espressione.

0

ho ricevuto questo messaggio di errore quando il mio oggetto array utilizzato nella funzione .Tutte è nullo Dopo aver inizializzato l'oggetto array, (upperSearchList nel tuo caso), l'errore è andato Il messaggio di errore è stato fuorviante in questo caso

dove upperSearchList.All (arg => person.someproperty.StartsWith (ARG)))

8

ho trovato la causa dell'errore (sto usando Framework 4.5). Il problema è che EF, un tipo complesso, passato nel parametro "Contains", non può essere tradotto in una query SQL. EF può utilizzare in una query SQL solo tipi semplici come int, string ...

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

GetAll fornisce un elenco di oggetti con un tipo complesso (ad esempio: "Funzione"). Quindi, proverei qui a ricevere un'istanza di questo tipo complesso nella mia query SQL, che naturalmente non può funzionare!

Se posso estrarre dalla mia lista, parametri che sono adatti alla mia ricerca, posso usare:

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

Ora EF non ha più il tipo complesso "Funzione" per lavorare, ma ad esempio con un semplice tipo (lungo). E questo funziona bene!

Problemi correlati