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
iClassTypes from new
parola chiave suLinq to Entity
queryLinq 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:
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
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}; }