L’entity framework non può essere costruita in una query LINQ to Entities

Esiste un tipo di entity framework chiamato prodotto generato dal framework di quadro. Ho scritto questa domanda

public IQueryable GetProducts(int categoryID) { return from p in db.Products where p.CategoryID== categoryID select new Product { Name = p.Name}; } 

Il seguente codice genera il seguente errore:

“L’ quadro o il tipo complesso Shop.Product non può essere costruito in una query LINQ to Entities”

 var products = productRepository.GetProducts(1).Tolist(); 

Ma quando uso select p invece di select new Product { Name = p.Name}; funziona correttamente

Come posso preformare una sezione di selezione personalizzata?

Non è ansible (e non dovrebbe essere ansible) proiettare su un’ quadro mappata. È ansible, tuttavia, proiettare su un tipo anonimo o su un DTO :

 public class ProductDTO { public string Name { get; set; } // Other field you may need from the Product entity } 

E il tuo metodo restituirà un elenco di DTO.

 public List GetProducts(int categoryID) { return (from p in db.Products where p.CategoryID == categoryID select new ProductDTO { Name = p.Name }).ToList(); } 

È ansible proiettare in un tipo anonimo e quindi da esso al tipo di modello

 public IEnumerable GetProducts(int categoryID) { return (from p in Context.Set() where p.CategoryID == categoryID select new { Name = p.Name }).ToList() .Select(x => new Product { Name = x.Name }); } 

Edit : Sarò un po ‘più specifico dato che questa domanda ha ottenuto molta attenzione.

Non è ansible proiettare direttamente nel tipo di modello (restrizione EF), quindi non c’è modo di aggirarlo. L’unico modo è di proiettare in un tipo anonimo (1a iterazione), quindi in un modello (seconda iterazione).

Tieni anche presente che quando si caricano parzialmente quadro in questo modo, non possono essere aggiornate, quindi devono rimanere separate, così come sono.

Non ho mai capito completamente perché questo non è ansible, e le risposte su questo thread non danno forti ragioni contro di esso (principalmente parlando di dati parzialmente caricati). È corretto che l’ quadro di stato parzialmente caricata non possa essere aggiornata, ma, quindi, questa quadro verrebbe distaccata, quindi i tentativi accidentali di salvarli non sarebbero possibili.

Considera il metodo che ho usato sopra: abbiamo ancora un’ quadro modello parzialmente caricata come risultato. Questa quadro è distaccata.

Considera questo codice (desiderio di esistere) ansible:

 return (from p in Context.Set() where p.CategoryID == categoryID select new Product { Name = p.Name }).AsNoTracking().ToList(); 

Questo potrebbe anche portare a un elenco di entity framework distaccate, quindi non avremmo bisogno di fare due iterazioni. Un compilatore sarebbe intelligente nel vedere che AsNoTracking () è stato usato, il che risulterà in quadro distaccate, quindi potrebbe permetterci di farlo. Se, tuttavia, AsNoTracking () è stato omesso, potrebbe generare la stessa eccezione che sta generando ora, per avvertirci che dobbiamo essere abbastanza specifici sul risultato che vogliamo.

C’è un altro modo in cui ho trovato dei lavori, devi build una class che deriva dalla tua class Product e usarla. Per esempio:

 public class PseudoProduct : Product { } public IQueryable GetProducts(int categoryID) { return from p in db.Products where p.CategoryID== categoryID select new PseudoProduct() { Name = p.Name}; } 

Non sono sicuro se questo è “permesso”, ma funziona.

Ecco un modo per farlo senza dichiarare una class adizionale:

 public List GetProducts(int categoryID) { var query = from p in db.Products where p.CategoryID == categoryID select new { Name = p.Name }; var products = query.ToList().Select(r => new Product { Name = r.Name; }).ToList(); return products; } 

Tuttavia, questo deve essere utilizzato solo se si desidera combinare più quadro in una singola quadro. La funzionalità di cui sopra (semplice prodotto per la mapping del prodotto) è fatta in questo modo:

 public List GetProducts(int categoryID) { var query = from p in db.Products where p.CategoryID == categoryID select p; var products = query.ToList(); return products; } 

Un altro modo semplice 🙂

 public IQueryable GetProducts(int categoryID) { var productList = db.Products .Where(p => p.CategoryID == categoryID) .Select(item => new Product { Name = item.Name }) .ToList() .AsQueryable(); // actually it's not useful after "ToList()" :D return productList; } 

Puoi usare questo e dovrebbe funzionare -> Devi usare toList prima di fare il nuovo elenco usando select:

 db.Products .where(x=>x.CategoryID == categoryID).ToList() .select(x=>new Product { Name = p.Name}).ToList(); 

aggiungi solo AsEnumerable ():

 public IQueryable GetProducts(int categoryID) { return from p in db.Products.AsEnumerable() where p.CategoryID== categoryID select new Product { Name = p.Name}; } 

In risposta all’altra domanda che è stata contrassegnata come duplicata ( vedi qui ) ho trovato una soluzione semplice e veloce basata sulla risposta di Soren:

 data.Tasks.AddRange( data.Task.AsEnumerable().Select(t => new Task{ creator_id = t.ID, start_date = t.Incident.DateOpened, end_date = t.Incident.DateCLosed, product_code = t.Incident.ProductCode // so on... }) ); data.SaveChanges(); 

Nota: questa soluzione funziona solo se si dispone di una proprietà di navigazione (chiave esterna) nella class Attività (qui chiamata “Incidente”). Se non lo hai, puoi semplicemente utilizzare una delle altre soluzioni pubblicate con “AsQueryable ()”.

Se si utilizza Entity framework, provare a rimuovere la proprietà da DbContext che utilizza il modello complesso come Entità I ha avuto lo stesso problema durante l’associazione di più modelli in un viewmodel denominato Entity

 public DbSet Entities { get; set; } 

Rimozione della voce da DbContext risolto il mio errore.

se si sta eseguendo Linq to Entity non è ansible utilizzare ClassType con new nella chiusura select della query only anonymous types are allowed (new without type)

dai un’occhiata a questo frammento del mio progetto

 //... var dbQuery = context.Set() .Include(letter => letter.LetterStatus) .Select(l => new {Title =l.Title,ID = l.ID, LastModificationDate = l.LastModificationDate, DateCreated = l.DateCreated,LetterStatus = new {ID = l.LetterStatusID.Value,NameInArabic = l.LetterStatus.NameInArabic,NameInEnglish = l.LetterStatus.NameInEnglish} }) ^^ without type__________________________________________________________________________________________________________^^ without type 

di voi ha aggiunto la new keyword in Seleziona chiusura anche sulle complex properties che otterrete questo errore

quindi remove i ClassTypes from new parola chiave su Linq to Entity query Linq to Entity ,,

perché verrà trasformato in istruzione sql ed eseguito su SqlServer

quindi quando posso usare new with types chiusura select ?

puoi usarlo se hai a che fare con LINQ to Object (in memory collection)

 //opecations in tempList , LINQ to Entities; so we can not use class types in select only anonymous types are allowed var tempList = dbQuery.Skip(10).Take(10).ToList();// this is list of  so we have to convert it so list of  //opecations in list , LINQ to Object; so we can use class types in select list = tempList.Select(l => new Letter{ Title = l.Title, ID = l.ID, LastModificationDate = l.LastModificationDate, DateCreated = l.DateCreated, LetterStatus = new LetterStatus{ ID = l.LetterStatus.ID, NameInArabic = l.LetterStatus.NameInArabic, NameInEnglish = l.LetterStatus.NameInEnglish } }).ToList(); ^^^^^^ with type 

dopo aver eseguito ToList su query è diventato in memory collection modo da poter utilizzare new ClassTypes in select

È ansible risolvere questo problema utilizzando Data Transfer Objects (DTO).

Questi sono un po ‘come i viewmodels in cui inserisci le proprietà di cui hai bisogno e puoi mapparle manualmente nel controller o utilizzando soluzioni di terze parti come AutoMapper.

Con DTO puoi:

  • Rendi i dati serializzabili (Json)
  • Sbarazzati di riferimenti circolari
  • Riduci il networktraffic lasciando le proprietà che non ti servono (viewmodelwise)
  • Usa l’objectflattening

Ho imparato questo a scuola quest’anno ed è uno strumento molto utile.

In molti casi, la trasformazione non è necessaria. Pensa al motivo per cui vuoi che il tipo sia fortemente elencato e valuta se desideri solo i dati, ad esempio, in un servizio web o per visualizzarlo. Non importa il tipo. Hai solo bisogno di sapere come leggerlo e controllare che sia identico alle proprietà definite nel tipo anonimo che hai definito. Questo è lo scenario di ottimizzazione, causa di qualcosa che non ha bisogno di tutti i campi di un’entity framework, e questo è il motivo per cui esiste un tipo anonimo.

Un modo semplice è questo:

 IEnumerable list = dataContext.Table.Select(e => new { MyRequiredField = e.MyRequiredField}).AsEnumerable(); 

puoi aggiungere AsEnumerable alla tua raccolta come segue:

 public IQueryable GetProducts(int categoryID) { return from p in db.Products.AsEnumerable() where p.CategoryID== categoryID select new Product { Name = p.Name}; }