Typ member Unterstützung für LINQ-to-Entities?
Ich habe eine MVC3-Projekt mit Entity Framework-Modell, in denen ich markiert eine Klasse wie folgt aus:
public partial class Product
{
public bool IsShipped
{
get { /* do stuff */ }
}
}
sind und welche ich verwenden möchte in einem LINQ-Ausdruck:
db.Products.Where(x => x.IsShipped).Select(...);
jedoch bekomme ich die folgende Fehlermeldung:
System.NotSupportedException wurde unhandled by user code Message=Die
angegeben Typ member 'IsShipped' wird nicht unterstützt LINQ to Entities.
Nur Initialisierungen, die juristische Mitglieder und entity navigation Eigenschaften
unterstützt werden. Source=System.Daten.Entity
Habe ich gegoogelt aber nicht gefunden, was definitiv über diese Nutzung habe ich versucht:
public partial class Product
{
public bool IsShipped()
{
/* do stuff */
}
}
db.Products.Where(x => x.IsShipped()).Select(...);
dann bekomme ich aber:
System.NotSupportedException wurde unhandled by user code Message=LINQ
zu Personen erkennt nicht die Methode " Boolean IsShipped ()' - Methode,
und diese Methode kann nicht übersetzt werden, in einen laden zu Ausdruck.
Source=System.Daten.Entity
gibt es Funktionen gibt, die ich nicht wollen, zu bauen, in der LINQ-Abfrage an sich... was ist ein guter Weg, dies zu behandeln?
* update *
Darin macht die gültigen Punkt, dass alles, was geschieht bei der Umsetzung von IsShipped
würde konvertiert werden müssen, um eine SQL-Abfrage und der compiler wahrscheinlich nicht wissen, wie es zu tun, so abrufen alle Objekte in den Speicher scheint die einzige Wahl (es sei denn eine direkte Abfrage an die Datenbank gemacht wird). Ich habe versucht es so:
IEnumerable<Product> xp = db.Quizes
.ToList()
.Where(x => !x.IsShipped)
.Select(x => x.Component.Product);
aber es erzeugt diesen Fehler:
Einer Beziehung Vielzahl Beschränkungsverletzung aufgetreten: Ein
EntityReference kann nicht mehr als ein Relevantes Objekt, aber die
Abfrage von mehr als einem zugehörigen Objekt. Dies ist ein nicht behebbarer
Fehler.
obwohl kurioserweise das funktioniert:
IEnumerable<Product> xp = db.Quizes
.ToList()
.Where(x => x.Skill.Id == 3)
.Select(x => x.Component.Product);
warum würde das sein?
* update II *
sorry, dass die Letzte Anweisung funktioniert auch nicht...
* update III *
Ich schließe diese Frage zugunsten der Verfolgung einer Lösung die hier vorgeschlagen werden, zu glätten, meine Logik in einer Abfrage - die Diskussion wird sich auf dieser post. Die zweite alternative, zum abrufen der gesamten ursprünglichen Abfrage in den Speicher, ist wahrscheinlich nicht akzeptabel, aber die Dritte, die die Umsetzung der Logik als eine direkte Abfrage an die Datenbank, sind jedoch noch nicht erforscht.
Danke an alle für den wertvollen input.
- Die "guten Weg, dies zu behandeln", völlig davon abhängt, was genau ist "das Zeugs". Die Frage ist, ob es etwas gibt, in die übersetzt werden können in SQL oder nicht. Wenn "das Zeugs" ist:
return MyMappedProp1 && MyMappedProp2
dann gibt es Hoffnung (nicht, wie Sie es jetzt tun, aber in einem anderen "TROCKENEN" Weg, wahrscheinlich). Wenn Sie öffnen eine Datei auf der Festplatte in "Sachen tun" und Lesen einen Wert aus, dann gibt es wahrscheinlich keine Hoffnung. Alle Allgemeinen Lösungen, die Sie zwingen wird, um die Abfrage mit LINQ to Objects, also alles laden in den Speicher, bevor Sie die filter. - Nein, ich nicht etwas zu tun, aber Datenbank-Abfragen in dem "Zeug"... aber, siehe meinen letzten update zu diesem posting
- Die Ausnahme in den "update": bekommt man diese auch, wenn Sie nur
IEnumerable<Product> xp = db.Quizes.ToList();
? Ich glaube, dieses problem hat nichts zu tun mit IhremIsShipped
Eigenschaft. Noch etwas ist falsch in dem Modell. - es hat zu tun mit Darin die Idee des Holens erstmal alles. Ich habe eine
IEnumerable
im Test, aber was ich wirklich wollte, war eine Liste, so betrachten, dassList<Product> p1 = db.Quizes.Select(x => x.Component.Product).ToList();
funktioniert gut, aberList<Product> p1 = db.Quizes.ToList().Select(x => x.Component.Product).ToList();
produziert, die Ausnahme. Ich brauche die Letzte.ToList()
da bin ich die Zuweisung an eine Liste...
Du musst angemeldet sein, um einen Kommentar abzugeben.
Der einzige Weg zu diesem "TROCKENEN" (nicht wiederholen die Logik innerhalb der
IsShipped
imWhere
- Klausel wieder) und vermeiden Sie das laden aller Daten in den Speicher, bevor Sie den filter anwenden wird, um die Inhalte derIsShipped
in einem Ausdruck. Sie können diesen Ausdruck als parameterWhere
und inIsShipped
als gut. Beispiel:Die Sie ausführen können Sie die Abfrage in etwa so:
Hier hätten Sie nur einen Ort, um die Logik in (
IsShippedExpression
) und dann verwenden Sie es für die Datenbank-Abfragen und in IhreIsShipped
Eigenschaft als gut.Kann ich dies tun? In den meisten Fällen wohl nicht, da die Kompilierung der Ausdruck ist sehr langsam. Es sei denn, die Logik ist sehr Komplex, wahrscheinlich ein Thema zu ändern, und ich bin in einer situation, wo die Leistung mit
IsShipped
egal, ich würde wiederholen Sie die Logik. Es ist immer möglich, zu extrahieren, die Häufig verwendet wird der Filter in eine extension-Methode:Und dann diese Art der Nutzung:
Würden Sie zwei Plätze, obwohl die Aufrechterhaltung der Logik: die
IsShipped
- Eigenschaft und die extension-Methode, aber dann kann man es wiederverwenden.Component
wirklich ist. "...Auf der Suche nach bestimmten Eigenschaften..." (zur Laufzeit) lässt mich denken, dass es einiger überlegung mit einbezogen, aber für mich ist Ihre Frage nicht greifbar genug, um eine Antwort zu geben. Anscheinend ist mein Beispiel-Modell oben ist zu einfach für das, was Sie wirklich versuchen, zu tun.Ich vermute
IsShipped
ist nicht zugeordnet, um ein Feld in der Datenbank? Das würde erklären, warum Linq to Entities beschwert - es kann nicht konstruieren Sie eine sql-Anweisung basiert auf dieser Eigenschaft.Ist Ihre
/* do stuff */
innerhalb der Eigenschaft basierend auf Feldern, die sind in der Datenbank? Wenn ja, könnten Sie diese Logik in Ihren.Where()
.Könnten Sie zuerst zu verbrauchen, das Ergebnis durch aufrufen
.ToList()
und führen Sie dann die filter auf der client-Seite:Natürlich sollten Sie sich bewusst sein, dass durch diese Weise werden Sie wahrscheinlich verlangsamen die Leistung Ihrer Anwendung als Datenbanken sind dabei, diese besten.
Ich nehme an, Sie meinen, Sie wollen führen Sie Abfragen aus, habe nichts zu tun mit der DB. Aber dein code stimmt nicht mit Ihrer Absicht. Blick auf diese Linie:
Den Teil, der sagt
db.Products
heißt, Sie wollen eine Abfrage der DB.Dieses Problem zu beheben, erhalten Sie ein Entitäten-set in den Speicher zuerst. Dann können Sie mit Linq to Objects auf stattdessen:
Den
.ToList()
beendet Sie Ihre erste DB-Abfrage, und gibt Ihnen eine in-memory-Repräsentation für die Arbeit mit und ändern Sie nach Ihren wünschen. Nach diesem Punkt kann man die Arbeit mit nicht-DB-Eigenschaften.Vorsichtig sein, dass, wenn du weitere DB-Operationen nach
ToList
(wie die Bearbeitung von DB-Eigenschaften für Entitäten, Abfragen aus Navigations-Eigenschaften, etc.), dann werden Sie wieder in Linq to Entities-land und nicht mehr in der Lage zu tun, Linq to Objects-Operationen. Sie können nicht direkt mischen die beiden.Und beachten Sie, dass, wenn
public bool IsShipped()
liest oder schreibt DB-Eigenschaften oder die navigation Eigenschaften, Sie könnten am Ende in Linq to Entities wieder, wenn Sie nicht vorsichtig sind.IsShipped
wichtig. Wenn es "eine Reihe von Datenbank-Abfragen", wie Sie es definieren? Unter der Decke sollte dies eine Art extended-join, evtl. mit sub-queries/temporäre Tabellen. Sie müssen möglicherweise geben Sie uns IhreIsShipped
Umsetzung und möglicherweise einige Ihrer DB-schema für uns, in der Lage weiter zu helfen.WhereIsShipped
Erweiterung MethodeIQueryable<Product>
. Habe ich diesen Ansatz zur Kapselung von paging-Logik vor, das ist einfach eine andere Art von Kriterien.