Die Entität kann nicht in einer LINQ to Entities-Abfrage erstellt werden

Es gibt einen Entitätstyp namens product, der vom Entity-Framework generiert wird. Ich habe diese Abfrage geschrieben

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

Der folgende Code triggers den folgenden Fehler aus:

“Die Entität oder der komplexe Typ Shop.Product kann nicht in einer LINQ to Entities-Abfrage erstellt werden”

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

Aber wenn ich select p anstatt select new Product { Name = p.Name}; es funktioniert richtig.

Wie kann ich einen benutzerdefinierten Auswahlbereich erstellen?

Sie können (und sollten nicht in der Lage sein) auf eine zugeordnete Entität zu projizieren. Sie können jedoch auf einen anonymen Typ oder auf ein DTO projizieren:

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

Und Ihre Methode gibt eine Liste der DTOs zurück.

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

Sie können in den anonymen Typ und dann in den Modelltyp projizieren

 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 : Ich werde etwas genauer sein, da diese Frage viel Aufmerksamkeit bekommt.

Sie können nicht direkt in den Modelltyp projizieren (EF-Einschränkung), daher gibt es keine Möglichkeit. Die einzige Möglichkeit besteht darin, in den anonymen Typ (1. Iteration) und dann in den Modelltyp (2. Iteration) zu projizieren.

Beachten Sie auch, dass beim teilweisen Laden von Entitäten auf diese Weise keine Aktualisierungen vorgenommen werden können. Daher sollten sie so wie sie sind getrennt bleiben.

Ich habe nie ganz verstanden, warum das nicht möglich ist, und die Antworten auf diesen Thread geben keine starken Gründe dagegen (hauptsächlich über teilweise geladene Daten). Es ist richtig, dass in einem teilweise geladenen Zustand die Entität nicht aktualisiert werden kann, aber dann würde diese Entität getrennt werden, so dass versehentliche Versuche, sie zu speichern, nicht möglich wären.

Beachten Sie die Methode, die ich oben verwendet habe: Wir haben immer noch eine teilweise geladene Modelleinheit. Diese Entität ist losgetriggers.

Betrachten Sie diesen (Wunsch-zu-existieren) möglichen Code:

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

Dies könnte auch zu einer Liste von getrennten Entitäten führen, sodass wir keine zwei Iterationen durchführen müssen. Ein Compiler wäre schlau, um zu sehen, dass AsNoTracking () verwendet wurde, was zu losgetriggersen Entitäten führen wird, so dass es uns erlauben könnte, dies zu tun. Wenn jedoch AsNoTracking () weggelassen würde, könnte es die gleiche Ausnahme casting, wie es jetzt wirft, um uns zu warnen, dass wir spezifisch genug sein müssen über das Ergebnis, das wir wollen.

Es gibt noch eine andere Möglichkeit, die ich gefunden habe: Sie müssen eine class erstellen, die von Ihrer Produktklasse abgeleitet ist und diese verwenden. Zum Beispiel:

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

Nicht sicher, ob das “erlaubt” ist, aber es funktioniert.

Hier ist eine Möglichkeit, dies zu tun, ohne zusätzliche class zu deklarieren:

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

Dies ist jedoch nur dann sinnvoll, wenn Sie mehrere Entitäten in einer Entität kombinieren möchten. Die obige functionalität (einfaches Produkt-zu-Produkt-Mapping) wird folgendermaßen durchgeführt:

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

Ein weiterer einfacher Weg 🙂

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

Sie können dies verwenden und es sollte funktionieren -> Sie müssen toList bevor Sie die neue Liste mit auswählen:

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

füge nur AsEnumerable () hinzu:

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

Als Antwort auf die andere Frage, die als Duplikat markiert wurde ( siehe hier ), habe ich eine schnelle und einfache Lösung gefunden, die auf der Antwort von Soren basiert:

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

Hinweis: Diese Lösung funktioniert nur, wenn Sie eine Navigationseigenschaft (Fremdschlüssel) für die Task-class (hier Incident genannt) haben. Wenn Sie das nicht haben, können Sie einfach eine der anderen veröffentlichten Lösungen mit “AsQueryable ()” verwenden.

Wenn Sie das Entity-Framework verwenden, versuchen Sie, die Eigenschaft aus DbContext zu entfernen, die Ihr komplexes Modell als Entität verwendet. Ich hatte das gleiche Problem, wenn Sie mehrere Modelle in ein View-Modell namens Entity mappen

 public DbSet Entities { get; set; } 

Das Entfernen des Eintrags von DbContext hat meinen Fehler behoben.

Wenn Sie Linq to Entity ClassType können Sie den ClassType mit new im select Closure der Abfrage verwenden. only anonymous types are allowed (new without type)

Schau dir diesen Ausschnitt meines Projekts an

 //... 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 

von Ihnen hinzugefügt das new keyword in Select Closure auch für die complex properties Sie diesen Fehler haben

remove die ClassTypes from new keyword in Linq to Entity queries,

weil es in sql-statement umgewandelt und auf SqlServer ausgeführt wird

also wann kann ich new with types bei select closure verwenden?

Sie können es verwenden, wenn Sie mit 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 

Nachdem ich die ToList Abfrage ausgeführt ToList , wurde sie in memory collection sodass wir new ClassTypes in select verwenden können

Sie können dies mithilfe von Datenübertragungsobjekten (DTOs) lösen.

Dies sind ein bisschen wie Ansichtsmodelle, wo Sie die Eigenschaften eingeben, die Sie benötigen, und Sie können sie manuell in Ihrem Controller oder mithilfe von Lösungen von Drittanbietern wie AutoMapper zuordnen.

Mit DTO’s können Sie:

  • Daten serialisierbar machen (Json)
  • Befreien Sie sich von zirkulären Referenzen
  • Verringern Sie den Netzwerkverkehr, indem Sie Eigenschaften verlassen, die Sie nicht benötigen (viewmodelwise)
  • Verwenden Sie die Objektflachung

Ich habe dieses Jahr in der Schule gelernt und es ist ein sehr nützliches Werkzeug.

In vielen Fällen wird die Transformation nicht benötigt. Denken Sie an den Grund, warum Sie die stark typisierte Liste möchten, und bewerten Sie, ob Sie die Daten beispielsweise in einem Web-Service oder zur Anzeige möchten. Es ist egal welcher Typ. Sie müssen nur wissen, wie Sie es lesen und prüfen, ob es mit den Eigenschaften übereinstimmt, die in dem von Ihnen definierten anonymen Typ definiert sind. Das ist das Optimun-Szenario, weil etwas nicht alle Felder einer Entität benötigt und daher der anonyme Typ existiert.

Ein einfacher Weg ist das:

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

Sie können AsEnumerable wie folgt in Ihre Sammlung aufnehmen:

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