2010-01-27 13 views
12

In meinem LINQ to SQL-Setup habe ich verschiedene Tabellen, die zu den Klassen zugeordnet werden, die im Grunde die gleiche Schnittstelle unterstützen die Versionierung zu unterstützen, dhein wiederverwendbares Prädikat für EntitySet machen <T>, IQueryable <T> und IEnumerable <T>

public interface IValid 
{ 
    int? validTo { get; } 
    int validFrom { get; } 
} 

Die LINQ to SQL-Klassen leiten sich von dieser Schnittstelle wie folgt aus:

public partial class representationRevision : IValid 
{ 
} 

Nun möchte ich eine DRY definieren möchten (Do not Repeat Yourself) Art des Filterns EntitySet<T>, IEnumerable<T> und IQueryable<T>, so dass die resultierenden Listen für eine bestimmte Revision gültig sind. Ich habe versucht, dies zu tun:

public static class ExtensionMethods 
{ 

    public static IQueryable<T> ValidFor<T>(this IQueryable<T> v, int? revision) 
     where T : IValid 
    { 
     return v.Where(cr => ((cr.validFrom <= revision) && 
      ((cr.validTo == null) || (cr.validTo > revision))) 
      || ((revision == null) && (cr.validTo == null)) 
      ); 
    } 
} 

Aber das gibt Probleme auf EntitySet<T>. Ich habe eine spezielle Implementierung für EntitySet hinzugefügt, die zuerst AsQueryable() aufruft, aber dies löst eine Ausnahme aus. Unbeeindruckt versuchte ich, ein Prädikat, so kann ich den Where(predicate) Ansatz verwenden zu machen: mit .Where<contentRevision>(IsValidFor(revision))

public static Expression<Func<contentRevision, bool>> IsValidFor(int? revision) 
    { 
     return ((cr) => ((cr.validFrom <= revision) && 
      ((cr.validTo == null) || (cr.validTo > revision))) 
      || ((revision == null) && (cr.validTo == null))); 
    } 

Bei der Verwendung gibt es Fehler wie:

Fehler 5 ‚System.Data.Linq.EntitySet‘ tut nicht enthalten eine Definition für ‚Wo‘ und die beste Erweiterung -Methodenüberladung
‚System.Linq.Enumerable.Where (System.Collections.Generic.IEnumerable, System.Func)‘ hat einige ungültige Argumente

Beachten Sie, dass dies auch ohne die Verwendung der IValid-Schnittstelle ... Ich habe versucht, alle Arten von Variationen über dieses Thema (wie das Hinzufügen des Int-Parameters), aber sie alle ausnahmslos zu scheitern scheinen. Irgendwelche Hinweise, um mich in die richtige Richtung zu bringen?

+0

In Ihrer statischen Ausdrucksfunktion oben ist der erste Typparameter 'contentRevision', ist das ein Tippfehler? Ich würde erwarten, dass es "IValid" ist. Auch der Fehler, den Sie unten zeigen, scheint ein Ergebnis der Übergabe eines Prädikats mit 3 Typparametern zu sein. Was passiert, wenn Sie das Prädikat wie gezeigt übergeben (Expression > ')? Ich habe das oft benutzt und es funktioniert gut, ich kann nicht aus deinem Beitrag herausfinden, warum dein Code nicht kompiliert wird. –

+0

Es ist in dem Kommentar unter dem Code "Beachten Sie, dass dies auch ohne Verwendung der IValid-Schnittstelle ist".Grundsätzlich habe ich versucht, es ohne IValid zuerst zum Laufen zu bringen, aber im Moment gibt es keinen Unterschied im Verhalten. Ich denke, es ist etwas mit EntitySet zu tun: Wenn ich meinen Code neu schreiben, um die Tabelle zu tun, scheint alles gut zu funktionieren. –

Antwort

4

Nicht sicher über EntitySet<T> so wird sich auf IQueryable<T> und IEnumerable<T> konzentrieren.

Damit der LINQ-Anbieter die Ausdrucksstrukturen auswerten kann, die IQueryable<T> für seine Ausdrucksargumente verwendet, muss sichergestellt werden, dass die zugrunde liegende Schnittstelle erhalten bleibt. Ansonsten tue alles in Bezug auf IEnumerable<T> (d. H., Wenn Sie OK sind, um das gesamte Dataset in den lokalen Speicher zu ziehen und es dort und nicht in der Datenbank zu verarbeiten, verwenden Sie einfach LINQ to Objects).

Die andere Option ist die AsQueryable Extension-Methode (Teil Queryable Klasse), die ein IEnumerable<T> zu einem IQueryable<T> umwandelt, und dann können Sie den Rest des Codes teilen.

IQueryable<T> SomeSharedQuery(this IQueryable<T> source) { 
    return source.(LINQ query operators...); 
} 
IQueryable<T> SomeSharedQuery(this IEnumerable<T> source) { 
    return source.AsQueryable().SomeSharedQuery(); 
} 

Sie haben also den gemeinsamen Code, mit einer Adaptermethode.

+1

Das funktioniert brillant, aber nicht für EntitySet obwohl. Die AsQueryable() hat (seltsamerweise) keine Übersetzung nach SQL. –

+0

@Matthijs: Bawed auf der Docs 'EntitySet 'implementiert' IEnumerable 'so erhalten Sie eine Übereinstimmung. Gegeben sei 'EntitySet 'ist über Lazy Laden von Teilen einer bestehenden Abfrage, die Sie nichts von einer' IQueryable 'Implementierung auf sie bekommen ... Wenn Sie möchten, dass die db die Arbeit über die Assoziation ausführen, gehören die im Original Abfrage. – Richard

+0

Wie funktioniert es nicht für 'EntitySet '? – svick

Verwandte Themen