2010-03-15 2 views
13

Angenommen, ich habe ein Objekt Einheit alsWiederverwenden von Linq to Entities' Expression <Func <T, TResult> in Auswählen und Wo ruft

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

Basierend auf einigen Eigenschaften eines Artikels, muss ich kann, wenn der Artikel bestimmen, gelöscht werden von einem bestimmten Benutzer. Also füge ich eine statische Methode hinzu, um die Überprüfung durchzuführen. Etwas wie:

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

So, jetzt kann ich

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 wieder zu verwenden, während eine Auswahl zu tun, so etwas wie:

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 nicht den Ausdruck in der select-Methode verwenden. Ich denke, wenn ich kann

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

Dann sollte ich in der Lage sein, den gleichen Ausdruck zu verwenden. Versucht, den Ausdruck zu kompilieren und ihn aufzurufen

aber es wird auch nicht funktionieren.

Irgendwelche Ideen, wie man das zum Laufen bringt? Oder wenn es nicht möglich ist, welche Alternativen gibt es, um die Geschäftslogik an beiden Orten wiederzuverwenden?

Dank

Pedro

+0

Das Zusammenstellen des Ausdrucks ist die richtige Wahl und es kompiliert und funktioniert für mich. Wenn ich es wäre, würde ich auch die Zusammenstellung herausrechnen. Welchen Fehler bekommst du? –

+0

Ja, es kompiliert einwandfrei, löst aber eine NotSupportedException-Ausnahme aus: "Der LINQ-Ausdrucksknotentyp 'Invoke' wird in LINQ to Entities nicht unterstützt." Versucht, den Ausdruck außerhalb des Select in einen Func zu kompilieren und ihn mit demselben Ergebnis zu verwenden. – Pedro

+0

Übrigens, wenn ich einen einfachen Func benutze und ihn in der Wobei Methode, dann wird die Abfrage auf dem Client ausgeführt, was nicht der beabsichtigte Zweck ist – Pedro

Antwort

4

Wiederverwendung von Ausdrucksbaumstrukturen ist eine schwarze Kunst; Sie können es tun, aber Sie müssten eine Menge Code zur Reflexion wechseln und Sie würden alle statischen Überprüfung verlieren. Insbesondere wird die Arbeit mit den anonymen Typen zum Albtraum (obwohl dynamic in 4.0 möglicherweise praktikabel ist).

Weiter, wenn Sie schummeln und Expression.Invoke verwenden, dann wird es nicht von allen Anbietern (am deutlichsten nicht auf EF in .NET 3.5SP1) unterstützt.

Wenn dies nicht ein großer Schwachpunkt ist, würde ich es mit Doppelarbeit verlassen. Oder brauchen Sie brauchen, um den Ausdrucksbaum wieder zu verwenden?

+1

Don ' "Ich brauche den Ausdrucksbaum wirklich zu verwenden. Es wurde nur versucht, nicht sicherheitsrelevanten Code zu duplizieren. Aber ich werde es für jetzt tun, und sehen, ob ich den Code später refaktorieren kann. Danke – Pedro

3

Was ich getan habe ist, ich PredicateBuilder verwendet, die eine Klasse in LinqKit ist und auch AsExpandable() http://www.albahari.com/nutshell/linqkit.aspx Ausdrücke aufzubauen und ich sie Statisch gespeichert als

public readonly Expression<Func<T,bool>> 

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

Wie die vorhergehende Frage von Marc Gravell andeutet, ist dieses ein Ding eine schwarze Kunst, aber glücklicherweise ist viel Arbeit von anderen Leuten gemacht worden.

Verwandte Themen