LINQ to Entities erkennt die Methode nicht

116

Beim Versuch, eine Linq-Abfrage durchzuführen, wird folgende Fehlermeldung angezeigt:

LINQ to Entities erkennt die Methode 'Boolean IsCharityMatching (System.String, System.String)' nicht und diese Methode kann nicht in einen Speicherausdruck übersetzt werden.

Ich habe viele frühere Fragen gelesen, bei denen derselbe Fehler auftritt. Wenn ich das richtig verstehe, liegt es daran, dass für LINQ to Entities der gesamte Linq-Abfrageausdruck in eine Serverabfrage übersetzt werden muss und Sie daher keine externe Methode aufrufen können drin. Ich konnte mein Szenario noch nicht in etwas umwandeln, das funktioniert, und mein Gehirn beginnt zu schmelzen. Ich hatte gehofft, jemand könnte mich in die richtige Richtung weisen. Wir verwenden Entity Framework und das Spezifikationsmuster (und ich bin neu in beiden).

Hier ist der Code, der die Spezifikation verwendet:

ISpecification<Charity> specification = new CharitySearchSpecification(charityTitle, charityReference);

charities = charitiesRepository.Find(specification).OrderBy(p => p.RegisteredName).ToList();

Hier ist der linq-Ausdruck:

public System.Linq.Expressions.Expression<Func<Charity, bool>> IsSatisfied()
{
    return p => p.IsCharityMatching(this.charityName, this.charityReference);
}

Hier ist die IsCharityMatching-Methode:

public bool IsCharityMatching(string name, string referenceNumber)
{
    bool exists = true;

    if (!String.IsNullOrEmpty(name))
    {
        if (!this.registeredName.ToLower().Contains(name.ToLower()) &&
            !this.alias.ToLower().Contains(name.ToLower()) &&
           !this.charityId.ToLower().Contains(name.ToLower()))
        {
            exists = false;
        }
    }

    if (!String.IsNullOrEmpty(referenceNumber))
    {
        if (!this.charityReference.ToLower().Contains(referenceNumber.ToLower()))
        {
            exists = false;
        }
    }

    return exists;
}

Lassen Sie mich wissen, wenn Sie weitere Informationen benötigen.

Danke vielmals,

Annelie

Annelie
quelle
Überprüfen Sie diese Antwort
Eranga
Werde das auch überprüfen, danke!
Annelie
1
Es wäre schön zu sehen, wie Sie verwenden, Find()wann Sie IsSatisfied()es verwenden.
Alisson

Antworten:

123

Wie Sie herausgefunden haben, kann Entity Framework Ihren C # -Code nicht als Teil seiner Abfrage ausführen. Es muss in der Lage sein, die Abfrage in eine tatsächliche SQL-Anweisung zu konvertieren. Damit dies funktioniert, müssen Sie Ihren Abfrageausdruck in einen Ausdruck umstrukturieren, den Entity Framework verarbeiten kann.

public System.Linq.Expressions.Expression<Func<Charity, bool>> IsSatisfied()
{
    string name = this.charityName;
    string referenceNumber = this.referenceNumber;
    return p => 
        (string.IsNullOrEmpty(name) || 
            p.registeredName.ToLower().Contains(name.ToLower()) ||
            p.alias.ToLower().Contains(name.ToLower()) ||
            p.charityId.ToLower().Contains(name.ToLower())) &&
        (string.IsNullOrEmpty(referenceNumber) ||
            p.charityReference.ToLower().Contains(referenceNumber.ToLower()));
}
StriplingWarrior
quelle
1
Wenn Sie Zweifel haben, suchen Sie es heraus: stackoverflow.com/questions/2352764/…
Chris Hayes
2
Die Rückgabe eines Konstruierten Expression<Func<T,type>>ist ein sehr guter Ansatz.
Travis J
Wie würden Sie dies in einem LINQ-Ausdruck verwenden? Ich würde so etwas gerne als wiederverwendbare Where-Klausel verwenden, habe aber Schwierigkeiten, sie umzusetzen.
Zorgarath
4
EDIT: egal, es wäre:context.Where(IsSatisfied())
Zorgarath
Schlüsselteil: "Entity Framework kann Ihren C # -Code nicht als Teil seiner Abfrage ausführen."
Alper
1

Ich habe den gleichen Fehler in diesem Code:

 var articulos_en_almacen = xx.IV00102.Where(iv => alm_x_suc.Exists(axs => axs.almacen == iv.LOCNCODE.Trim())).Select(iv => iv.ITEMNMBR.Trim()).ToList();

das war genau der fehler:

System.NotSupportedException: 'LINQ to Entities erkennt die Methode' Boolean Exists (System.Predicate`1 [conector_gp.Models.almacenes_por_sucursal]) 'nicht und diese Methode kann nicht in einen Speicherausdruck übersetzt werden.'

Ich habe es so gelöst:

var articulos_en_almacen = xx.IV00102.ToList().Where(iv => alm_x_suc.Exists(axs => axs.almacen == iv.LOCNCODE.Trim())).Select(iv => iv.ITEMNMBR.Trim()).ToList();

Ich habe vor meiner Tabelle eine .ToList () hinzugefügt, die den Entity- und den Linq-Code entkoppelt und verhindert, dass mein nächster Linq-Ausdruck übersetzt wird

ANMERKUNG: Diese Lösung ist nicht optimal, da die Entitätsfilterung vermieden wird und einfach alle Tabellen in den Speicher geladen werden

Ing. Gerardo Sánchez
quelle
1
Meistens ist dies die einfachste Lösung, aber um nicht das gesamte Objekt zu laden, treffe ich normalerweise eine anonyme Auswahl vor der .ToList () mit genau dem, was ich brauche ... xx.Select (x => new {x.Id, x.DateTimeUpdate }). ToList (). Select (x => new {x.Id, DateTimeUpdate = x.DateTimeUpdate.ToString ("TT / MM / JJJJ")})
Diógenes
0

Wenn jemand nach einer VB.Net-Antwort sucht (wie ich es ursprünglich war), hier ist sie:

Public Function IsSatisfied() As Expression(Of Func(Of Charity, String, String, Boolean))

Return Function(charity, name, referenceNumber) (String.IsNullOrWhiteSpace(name) Or
                                                         charity.registeredName.ToLower().Contains(name.ToLower()) Or
                                                         charity.alias.ToLower().Contains(name.ToLower()) Or
                                                         charity.charityId.ToLower().Contains(name.ToLower())) And
                                                    (String.IsNullOrEmpty(referenceNumber) Or
                                                     charity.charityReference.ToLower().Contains(referenceNumber.ToLower()))
End Function
Mik
quelle
-1

Ich hatte ein ähnliches Problem wie Sie und diese LINQ-Dokumentation hat mir geholfen, die richtigen Zeichenfolgenfunktionen zu finden, um die Einschränkungen zu umgehen.

Michael Fayad
quelle