Bernhard  GrojerLINQ Provider - Vom Ausdruck zum Ergebnis - Teil 2



Teil 2 von der Blog-Serie zum Thema LINQ Provider.
Bevor Sie hier weiterleisen sollten
Teil 1 gelesen haben.


Im ersten Teil haben wir bereits Basistechnologien abgesteckt und die Hintergründe schon etwas umschifft.
Wir sind weiteres dazu übergegangen uns mit 2 Basisklassen auseinanderzusetzen.

Auf der einen Seite haben wir uns dafür Query<T> bereit gestellt, die die eigentliche “Ergebnismenge” in Zukunft repräsentieren soll.
zB eine Liste von Kunden, Mitarbeitern, Produkten usw. usf.
Auf der anderen Seite hatten wir noch den QueryProvider, der den eigentlichen Gang zur Datenquelle, anhand der Basis-Interaces erstellt.

Zuerst beginnen wir nun die Funktionalitäten in Query<T> umzusetzen:

Hierfür wird es allerdings notwendig, dass wir eine Instanz unseres QueryProvider in dieser Klasse halten können und weiteres einen entsprechenden Konstrukter bereitstellen, der einen QueryProvider sowie optional einen ExpressionTree von LINQ entgegennimmt.
Wurde uns durch LINQ kein entsprechender ExpressionTree weitergegeben erzeugen wir uns eine ConstantExpression die unsere Ergebnismenge nicht weiter einschränkt.

public class Query<T> : IOrderedQueryable<T>, IQueryable, IOrderedQueryable
    {
        QueryProvider _Provider;
        Expression _Expression;

        public Query(QueryProvider provider)
        {
            this._Provider = provider;
            this._Expression = Expression.Constant(this);
        }

        public Query(QueryProvider provider, Expression expression)
            : this(provider)
        {
            this._Expression = expression;
        }

       //Implementierung der Interfaces ...
    }

Bei der Implementierung des Interfaces machen wir nun nichts anderes als “jeweils” Provider.Execute(…) aufzurufen und diesen unsere Expression weitergereicht.
Die Auswertung und auch der Gang zur Datenquelle obliegt nun unserem Provider.

    public class Query<T> : IOrderedQueryable<T>, IQueryable, IOrderedQueryable
    {
       //...

        public IEnumerator<T> GetEnumerator()
        {
            var r = this.Provider.Execute<IEnumerable<T>>(this._Expression) as IEnumerable<T>;
            return r.GetEnumerator();
        }
        IEnumerator IEnumerable.GetEnumerator()
        {
            var r = this.Provider.Execute(this._Expression) as IEnumerable;
            return r.GetEnumerator();
        }
  
       //...
     }

Und somit sind wir nun auch einem Geheimnis von LINQ auf die Schliche gekommen, weshalb Abfragen üblicherweise erst bei Zugriff ausgeführt werden.
Den Erst das Triggern von GetEnumerator() ruft die Execute Methode unseres Providers auf.

Unsere nächste Aufgabe wird somit ein Umsetzung unserer Provider-Basisklasse werden. Mehr dazu jedoch im 3ten Teil.

Sie möchten mehr wissen zum Thema? Auf der ADC08 gibt es eine Session von mir:



Kategorien: 07.10.2008 11:03:15


 


Neuen Kommentar einfügen:

  Titel:     
  Name:  
  E-Mail:
  Kommentar:

 
 
 


Kommentare




© Copyright 2008 ppedv AG