Frage

Ich habe einen Linq-Anbieter, der erfolgreich geht und erhält Daten von meiner gewählten Datenquelle, aber was ich jetzt tun, dass ich meine gefiltert resultset habe, ist Linq zu Objekten erlaubt den Rest des Ausdrucksbaumes zu verarbeiten (für Dinge wie Joins, Projektion etc.)

Mein Gedanke war, dass ich konnte einfach den Ausdruck Konstante ersetzen, die meine IQueryProvider mit den Ergebnis-Sets IEnumerable über eine Expression enthält und dann diesen neuen Ausdruck zurück. Auch das Rück der IEnumerable des Anbieters von meinem IQueryable ... aber das scheint nicht zu funktionieren: - (

Jede Idee?

Edit: Einige gute Antworten hier, aber die Form gegeben ...

var qry = from c in MyProv.Table<Customer>()
          Join o in MyProv.Table<Order>() on c.OrderID equals o.ID
          select new 
          {
            CustID = c.ID,
            OrderID = o.ID
          }

In meinem Provider kann ich leicht die 2 Resultsets von Kunden und Bestellungen zurück, wenn die Daten aus einer SQL-Quelle war, würde ich nur konstruieren und passieren auf dem SQL-Join-Syntax, aber es dieser Fall die Daten nicht aus einer SQL Quelle so muß ich in Code die Verbindung tun ... aber wie gesagt, ich habe die 2 Ergebnismengen und Linq zu Objekten kann eine Verknüpfung tun ... (und später die Projektion) es wirklich schön wäre, nur der Ersatz Expression Konstanten MyProv.Table<Customer> und MyProv.Table<Order> mit List<Customer> und List<Order> und lassen einen List<> Provider Prozess den Ausdruck ... ist das möglich? wie?

War es hilfreich?

Lösung 2

Die Art der Sache, die ich nach der Abfragbare wurde ersetzt <> Konstante im Ausdrucksbaum mit einem konkreten IEnumerable (oder IQueryable über .AsQueryable ()) Ergebnismenge ... dies ist ein komplexes Thema, das wahrscheinlich nur jeder macht Sinn Linq Provider Autoren, die Knie sind tief im Ausdrucksbaum Besucher etc.

ich einen Ausschnitt auf dem Msdn Durchlauf gefunden, der etwas tut, was ich nach bin, das gibt mir einen Weg nach vorn ...

using System;
using System.Linq;
using System.Linq.Expressions;

namespace LinqToTerraServerProvider
{
    internal class ExpressionTreeModifier : ExpressionVisitor
    {
        private IQueryable<Place> queryablePlaces;

        internal ExpressionTreeModifier(IQueryable<Place> places)
        {
            this.queryablePlaces = places;
        }

        internal Expression CopyAndModify(Expression expression)
        {
            return this.Visit(expression);
        }

        protected override Expression VisitConstant(ConstantExpression c)
        {
            // Replace the constant QueryableTerraServerData arg with the queryable Place collection.
            if (c.Type == typeof(QueryableTerraServerData<Place>))
                return Expression.Constant(this.queryablePlaces);
            else
                return c;
        }
    }
}

Andere Tipps

Beide der vorherigen Antworten arbeiten, aber es liest besser, wenn man AsEnumerable () verwenden, die IQueryable zu IEnumerable werfen:

// Using Bob's code...
var result = datacontext.Table
   .Where(x => x.Prop == val)
   .OrderBy(x => x.Prop2)
   .AsEnumerable()  //  <---- anything after this is done by LINQ to Objects
   .Select(x => new { CoolProperty = x.Prop, OtherProperty = x.Prop2 });

EDIT:

// ... or MichaelGG's
var res = dc.Foos
           .Where(x => x.Bla > 0)  // uses IQueryable provider
           .AsEnumerable()
           .Where(y => y.Snag > 0); // IEnumerable, uses LINQ to Objects

Wenn Sie ein Repository Pattern implementiert Sie mit nur Bereitstellung eines IQueryable zurück und abstrahieren den Tisch weg konnte.

Beispiel:

var qry = from c in MyProv.Repository<Customer>()
          Join o in MyProv.Repository<Order>() on c.OrderID equals o.ID
          select new 
          {
            CustID = c.ID,
            OrderID = o.ID
          }

und dann bauen Sie einfach Ihren Provider die IQueryable Muster in Ihrer Repository-Methode zu modellieren wie dieser Artikel zeigt.

Auf diese Weise können Sie alle Arten von Anbietern schreiben zu verwenden, was auch immer Sie brauchen. Sie können eine LINQ 2 SQL-Provider haben, oder ein im Speicher-Anbieter für Ihre Unit-Tests schreiben.

Die Repository-Methode für den LINQ 2 SQL-Anbieter würde wie folgt aussehen:

public IQueryable<T> Repository<T>() where T : class
{
    ITable table = _context.GetTable(typeof(T));
    return table.Cast<T>();
}

Es sei denn, ich bin Missverständnis, ich in der Regel nur hinzufügen .ToArray () in der Kette von Linq Methoden an dem Punkt, wo ich den Linq-Anbieter ausgeführt werden soll.

Zum Beispiel (man denke Linq to SQL)

var result = datacontext.Table
   .Where(x => x.Prop == val)
   .OrderBy(x => x.Prop2)
   .ToArray()
   .Select(x => new {CoolProperty = x.Prop, OtherProperty = x.Prop2});

So durch SortiertNach () wird in SQL übersetzt, aber die Select () ist LINQ to Objects.

Robs Antwort ist gut, aber zwingt vollständige Aufzählung. Sie könnten werfen Extension-Methode Syntax und lazy evaluation zu halten:

var res = ((IEnumerable<Foo>)dc.Foos
            .Where(x => x.Bla > 0))  // IQueryable
          .Where(y => y.Snag > 0)   // IEnumerable
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top