Sto riscontrando problemi nella creazione di una query LINQ di Entity Framework la cui clausola select contiene chiamate di metodo a oggetti non EF.Seleziona clausola contenente chiamate al metodo non EF
Il codice seguente fa parte di un'app utilizzata per trasformare i dati da un DBMS in uno schema diverso su un altro DBMS. Nel codice qui sotto, Ruolo è la mia classe personalizzata correlati ai DBMS, e le altre classi sono tutti generati da Entity Framework dal mio schema DB:
// set up ObjectContext's for Old and new DB schemas
var New = new NewModel.NewEntities();
var Old = new OldModel.OldEntities();
// cache all Role names and IDs in the new-schema roles table into a dictionary
var newRoles = New.roles.ToDictionary(row => row.rolename, row => row.roleid);
// create a list or Role objects where Name is name in the old DB, while
// ID is the ID corresponding to that name in the new DB
var roles = from rl in Old.userrolelinks
join r in Old.roles on rl.RoleID equals r.RoleID
where rl.UserID == userId
select new Role { Name = r.RoleName, ID = newRoles[r.RoleName] };
var list = roles.ToList();
Ma chiamando ToList mi dà questo NotSupportedException:
LINQ alle entità non riconosce il metodo 'Int32 get_Item (System.String)' metodo e questo metodo non può essere tradotto in un'espressione negozio
Suoni come LINQ-to-Entities sono barfing sulla mia chiamata per estrarre il valore dal dizionario dato il nome come chiave. Ovviamente non capisco abbastanza di EF per sapere perché questo è un problema.
Sto utilizzando il provider di strutture di entità dotConnect for PostgreSQL di devart, anche se presumo a questo punto che questo non sia un problema specifico di DBMS.
so che posso farlo funzionare, dividendo il mio query in due query, in questo modo:
var roles = from rl in Old.userrolelinks
join r in Old.roles on rl.RoleID equals r.RoleID
where rl.UserID == userId
select r;
var roles2 = from r in roles.AsEnumerable()
select new Role { Name = r.RoleName, ID = newRoles[r.RoleName] };
var list = roles2.ToList();
ma mi chiedevo se ci fosse un modo più elegante e/o più efficiente per risolvere questo problema , idealmente senza dividerlo in due domande.
In ogni caso, la mia domanda è due parti:
Prime, posso trasformare questa query LINQ in qualcosa che Entity Framework accetterà, idealmente senza suddivisione in due pezzi?
In secondo luogo, mi piacerebbe anche capire un po 'di EF, quindi posso capire perché EF non può stratificare il mio codice .NET personalizzato in cima all'accesso del DB. Il mio DBMS non ha idea di come chiamare un metodo su una classe Dictionary, ma perché EF non può semplicemente effettuare tali chiamate con il metodo Dictionary dopo che ha già estratto i dati dal DB? Certo, se volessi comporre più query EF insieme e mettere il codice .NET personalizzato nel mezzo, mi aspetterei che fallisca, ma in questo caso il codice .NET è solo alla fine, quindi perché è un problema per EF? Presumo che la risposta sia qualcosa del tipo "quella caratteristica non è stata convertita in EF 1.0" ma sto cercando un po 'di spiegazioni sul perché questo è abbastanza difficile da giustificare il fatto di lasciarlo fuori da EF 1.0.
Sembra che abbia sopravvalutato l'intelligenza di LINQ alle entità. Avevo pensato che L-to-E fosse abbastanza intelligente da scomporre un albero di espressioni nella parte che il DB può gestire, e un'altra parte che doveva risolvere usando chiamate .NET (fuori dal DB), e poi ricucire i due insieme. Se ti capisco bene, stai dicendo che L-to-E non è così intelligente, che semplicemente cerca di trasformare * tutto * nell'espressione in SQL, e se c'è qualcosa che non può trasformare (ad es. chiamata a un metodo oggetto .NET nella clausola select), quindi non riuscirà a eseguire? –
Proprio così, Justin. Nota: sezionare una query tra i livelli automaticamente, si tratta di una 'query distribuita', che è un problema incredibilmente difficile da risolvere in generale. –
Giusto. LINQ to Entities contiene tutto come un albero di espressioni che verrà utilizzato contro il database solo quando è * effettivamente * iterato. È "stupido" in questo modo, ma è perché, come dice Alex, le query distribuite sono un problema incredibilmente difficile da risolvere quando le cose diventano anche un po 'complesse. Sappiate che, tuttavia, è possibile utilizzare l'iterazione come segnalibro per estrarre i dati dal client. –