Es werden nur Initialisierer, Entitätsmitglieder und Entitätsnavigationseigenschaften unterstützt

102

Ich bekomme diese Ausnahme:

Das angegebene Typmitglied 'Bezahlt' wird in LINQ to Entities nicht unterstützt. Es werden nur Initialisierer, Entitätsmitglieder und Entitätsnavigationseigenschaften unterstützt.

    public ActionResult Index()
    {
        var debts = storeDB.Orders
            .Where(o => o.Paid == false)
            .OrderByDescending(o => o.DateCreated);

        return View(debts);
    }

Meine Modellklasse

public partial class Order
{
    public bool Paid {
        get {
            return TotalPaid >= Total;
        }
    }

    public decimal TotalPaid {
        get {
            return Payments.Sum(p => p.Amount);
        }
    }

Zahlungen ist eine verwandte Tabelle, die den Feldbetrag enthält. Die Abfrage funktioniert, wenn ich die Where-Klausel entferne, die korrekte Informationen zu den Zahlungen enthält. Gibt es einen Hinweis darauf, was mit dem Code nicht stimmt?

Gelöst wie die Antwort vorgeschlagen mit:

    public ActionResult Index()
    {
        var debts = storeDB.Orders
            .OrderByDescending(o => o.DateCreated)
            .ToList()
            .Where(o => o.Paid == false);

        return View(debts);
    }
Marc
quelle
15
Einfache Antwort: Sie können keine nicht zugeordneten Eigenschaften in Linq-to-Entities-Abfragen verwenden! Nur zugeordnete Eigenschaften werden in SQL übersetzt.
Ladislav Mrnka

Antworten:

114

Die Entität versucht, Ihre Paid-Eigenschaft in SQL zu konvertieren und kann dies nicht, da sie nicht Teil des Tabellenschemas ist.

Sie können Entity die Tabelle ohne bezahlten Filter abfragen lassen und dann die nicht bezahlten herausfiltern.

public ActionResult Index()
{
    var debts = storeDB.Orders
        //.Where(o => o.Paid == false)
        .OrderByDescending(o => o.DateCreated);

    debts = debts.Where(o => o.Paid == false);

    return View(debts);
}

Das würde natürlich bedeuten, dass Sie alle Daten auf den Webserver zurückbringen und die Daten darauf filtern. Wenn Sie auf dem DB-Server filtern möchten, können Sie eine berechnete Spalte in der Tabelle erstellen oder eine gespeicherte Prozedur verwenden.

Eugene S.
quelle
25

Musste nur ein ähnliches Problem lösen. Die oben genannten Lösungen erfordern eine In-Memory-Verarbeitung, was eine schlechte Praxis ist (verzögertes Laden).

Meine Lösung bestand darin, einen Helfer zu schreiben, der ein Prädikat zurückgab:

public static class Extensions
{
    public static Expression<Func<Order, bool>> IsPaid()
    {
        return order => order.Payments.Sum(p => p.Amount) >= order.Total;
    }
}

Sie können Ihre linq-Anweisung wie folgt umschreiben:

var debts = storeDB.Orders
                    .Where(Extensions.IsPaid())
                    .OrderByDescending(o => o.DateCreated);

Dies ist praktisch, wenn Sie die Berechnungslogik (DRY) wiederverwenden möchten. Nachteil ist, dass die Logik nicht in Ihrem Domain-Modell ist.

Koen Luyten
quelle
1
Es gibt eine Reihe von Bibliotheken, die versuchen, diesen Ansatz "integrierter" zu gestalten, siehe: stackoverflow.com/a/27383641/470183 . Linq-to-Entities ist auf Ausdrücke beschränkt, die die "Canonical Functions" verwenden - die in SQL umgewandelt werden können. C # 6 führte "Expression bodied functions" ein, aber dies sind keine echten Lambdas (siehe: stackoverflow.com/a/28411444/470183 ). Trotzdem wäre es gut, dies im Rahmen zu haben, daher die WIBNI data.uservoice.com/forums/…
James Close
1
Vielen Dank für dieses einfache und prägnante Beispiel von Expression<Func<xx,yy>>. Ich habe es schon einmal verstanden, aber jetzt sieht es offensichtlich aus.
AlexB
17

Dieses Problem kann auch von einer [NotMapped]Eigenschaft herrühren, die in Ihrem DB-Modell und Ansichtsmodell denselben Namen hat.

AutoMapper versucht, es während einer Projektion aus der Datenbank auszuwählen. und die NotMapped-Eigenschaft ist offensichtlich nicht in der Datenbank vorhanden.

Die Lösung besteht in Ignoreder Eigenschaft in der AutoMapper-Konfiguration beim Zuordnen vom DB-Modell zum Ansichtsmodell.

  1. Suchen Sie in Ihrem DB-Modell nach einer [NotMapped]Eigenschaft mit Namen Foo.
  2. Suchen Sie Fooin Ihrem Ansichtsmodell nach einer gleichnamigen Eigenschaft .
  3. Wenn dies der Fall ist, ändern Sie Ihre AutoMapper-Konfiguration. Hinzufügen.ForMember(a => a.Foo, b => b.Ignore());
Jess
quelle
Dang AutoMapper Projection hat mich auch erwischt, danke für die Antwort!
Chase Florell
15

Linq konvertiert die Anweisungen in SQL-Anweisungen und führt sie in eine Datenbank aus.

Diese Konvertierung erfolgt jetzt nur für Entitätsmitglieder, Initialisierer und Entitätennavigationseigenschaften. Um eine Funktion zu erreichen oder einen Eigenschaftenvergleich zu erhalten, müssen wir sie zuerst in eine In-Memory-Liste konvertieren und dann eine Funktion anwenden, um Daten abzurufen.

Daher insgesamt

var debts = storeDB.Orders.toList()
        .Where(o => o.Paid == false)
        .OrderByDescending(o => o.DateCreated);
T Gupta
quelle
21
Ich würde vorschlagen, dass es gefährlich ist, jemanden zu bitten, eine toList () für Bestellungen zu erstellen, da dies bedeuten würde, die gesamte Liste
abzurufen
Dies ist gut für mich, da sich meine problematische Eigenschaft in einer Sum Linq-Funktion befindet, die nicht in der Where-Klausel enthalten ist. Ich erhalte also keine unnötigen Daten und mache auf den empfangenen Daten die Linq-Summenfunktion, die an der Liste arbeitet. Danke dir! Was auf den ersten Blick schlecht aussieht, kann in bestimmten Situationen sehr hilfreich sein!
Dov Miller
11

Der andere wahrscheinliche Grund ist, dass Sie IEnumerablefür Ihre Immobilie verwenden, anstattICollection

Also statt:

public class This
{
    public long Id { get; set; }
    //...
    public virtual IEnumerable<That> Thats { get; set; }
}

Mach das:

public class This
{
    public long Id { get; set; }
    //...
    public virtual ICollection<That> Thats { get; set; }
}

Und du bist ein hunky dory ... dummes Ding, 2 Stunden zu verlieren.

Serj Sagan
quelle
2

Diese Situation kann auch auftreten, wenn Sie von EntityFramework nicht unterstützte Typen verwenden , z. B. int ohne Vorzeichen.

Dies war mein Fall eines solchen Fehlers.

Weitere Informationen zu unterstützten Typen finden Sie unter: https://msdn.microsoft.com/en-us/library/ee382832(v=vs.100).aspx

Es gibt einige Problemumgehungen für solche Situationen, die von GFoley83 erläutert werden: Wie werden vorzeichenlose int / long-Typen mit Entity Framework verwendet?

Ony
quelle
Dieser Link hat viel Zeit gespart! Vielen Dank!
Vladimir Semashkin
0

Ich war mit diesem Problem konfrontiert, weil ich eine Mitgliedsvariable mit nur einer get without setEigenschaft hatte

das heißt es ist auto calculatedund not storedals spalte inthe table

deshalb ist es not existin dertable schema

so make suredass jede Mitgliedsvariable not auto calculatedzu havea getterund setterEigenschaften

Basheer AL-MOMANI
quelle
-1

Ihr edmx- und Kontextmodell haben eine andere Eigenschaft, die neu in db hinzugefügt wird.

Aktualisieren Sie Ihr EDMX, aktualisieren Sie es ordnungsgemäß. Bauen Sie Ihr Projekt auf und führen Sie es erneut aus.

Es wird Ihr Problem lösen.

Grüße, Ganesh Nikam

Ganesh Nikam
quelle