14 Stimmen

Wiederverwendung von Linq to Entities' Expression<Func<T, TResult> in Select- und Where-Aufrufen

Angenommen, ich habe ein Entitätsobjekt, das als

public partial class Article  
{  
    public Id
    {
        get;
        set;
    }  
    public Text
    {
        get;
        set;
    }  
    public UserId
    {
        get;
        set;
    }  
}

Anhand einiger Eigenschaften eines Artikels muss ich feststellen, ob der Artikel von einem bestimmten Benutzer gelöscht werden kann. Also füge ich eine statische Methode hinzu, um die Überprüfung durchzuführen. Etwa so:

public partial class Article  
{  
    public static Expression<Func<Article, bool>> CanBeDeletedBy(int userId)
    {  
        //Add logic to be reused here
        return a => a.UserId == userId;
    }  
}

Jetzt kann ich also

using(MyEntities e = new MyEntities())  
{
    //get the current user id
    int currentUserId = 0;

    e.Articles.Where(Article.CanBeDeletedBy(currentUserid));  
}

So weit, so gut. Jetzt möchte ich die Logik in CanBeDeletedBy wiederverwenden, während ich ein Select mache, etwa so:

using(MyEntities e = new MyEntities())  
{
    //get the current user id
    int currentUserId = 0;

    e.Articles.Select(a => new  
    {  
        Text = a.Text,  
        CanBeDeleted = ???  
    };  
}

Aber egal, was ich versuche, ich kann den Ausdruck nicht in der Select-Methode verwenden. Ich vermute, dass wenn ich tun kann

    e.Articles.Select(a => new  
    {  
        Text = a.Text,  
        CanBeDeleted = a => a.UserId == userId
    };  

Dann sollte ich in der Lage sein, denselben Ausdruck zu verwenden. Ich habe versucht, den Ausdruck zu kompilieren und ihn aufzurufen, indem ich

    e.Articles.Select(a => new  
    {  
        Text = a.Text,  
        CanBeDeleted = Article.CanBeDeletedBy(currentUserId).Compile()(a)
    }; 

aber auch das wird nicht funktionieren.

Haben Sie eine Idee, wie man das zum Laufen bringen kann? Oder wenn das nicht möglich ist, welche Alternativen gibt es, um die Geschäftslogik an beiden Stellen wiederzuverwenden?

Danke

Pedro

0 Stimmen

Die Kompilierung des Ausdrucks ist die richtige Wahl, und sie funktioniert auch bei mir. An meiner Stelle würde ich auch die Kompilierung ausschließen. Welche Fehlermeldung erhalten Sie?

0 Stimmen

Ja, es kompiliert gut, aber wirft eine NotSupportedException Ausnahme: "Der LINQ-Ausdrucksknotentyp 'Invoke' wird in LINQ to Entities nicht unterstützt." Ich habe versucht, den Ausdruck außerhalb von Select in einen Func<Artikel,bool> zu kompilieren und ihn innerhalb zu verwenden, mit demselben Ergebnis.

0 Stimmen

Btw, wenn ich eine einfache Func<Artikel, bool>, und verwenden Sie es in der Where-Methode, dann wird die Abfrage auf dem Client ausgeführt werden, die nicht den beabsichtigten Zweck ist.

4voto

Marc Gravell Punkte 970173

Die Wiederverwendung von Ausdrucksbäumen ist eine schwarze Kunst; Sie können es tun, aber Sie müssten eine Menge Code auf Reflexion umstellen und Sie würden alle statischen Überprüfungen verlieren. Insbesondere die Arbeit mit den anonymen Typen wird zum Alptraum (obwohl dynamic in 4.0 könnte machbar sein).

Außerdem, wenn Sie schummeln und die Expression.Invoke dann wird es nicht von allen Anbietern unterstützt (vor allem nicht von EF in .NET 3.5SP1).

Wenn es sich nicht um ein großes Problem handelt, würde ich es bei der Duplikation belassen. Oder tun Sie brauchen um den Ausdrucksbaum wiederzuverwenden?

1 Stimmen

Sie müssen den Ausdrucksbaum nicht unbedingt wiederverwenden. Es war nur zu versuchen, nicht zu duplizieren sicherheitsrelevanten Code. Aber ich werde es für jetzt tun, und sehen, wenn ich den Code später refaktorisieren kann. Danke

3voto

Was ich tat, ist ich verwendet PredicateBuilder, die eine Klasse in LinqKit und auch AsExpandable() ist http://www.albahari.com/nutshell/linqkit.aspx um Ausdrücke zu erstellen, und ich habe sie statisch als

public readonly Expression<Func<T,bool>>

in einer statischen Klasse. Jeder Ausdruck baute auf einem vorherigen Ausdruck auf, wodurch die Anzahl der Duplikate reduziert wurde.

Wie die vorangegangene Frage von Marc Gravell andeutet, ist dies eine schwarze Kunst, aber glücklicherweise wurde ein großer Teil der Arbeit von anderen Personen geleistet.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X