Esecuzione di parte di una query IQueryable e rinvio del resto a Linq for Objects

c# expression-trees iqueryable linq

Domanda

Ho un provider Linq che va con successo e ottiene i dati dalla mia origine dati scelta, ma quello che vorrei fare ora che ho il mio set di risultati filtrato, è consentire a Linq to Objects di elaborare il resto dell'albero Expression (per cose come Joins, proiezione ecc.)

Il mio pensiero era che potevo semplicemente sostituire la costante di espressione che contiene il mio IQueryProvider con i set di risultati IEnumerable tramite un ExpressionVisitor e quindi restituire quella nuova espressione. Restituisce anche il provider IEnumerable dal mio IQueryable ... ma questo non sembra funzionare :-(

Qualche idea?

Modifica: alcune buone risposte qui, ma dato il modulo ...

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
          }

Nel mio provider posso facilmente recuperare i 2 set di risultati da clienti e ordini, se i dati provenivano da un'origine SQL, vorrei solo costruire e passare la sintassi Join di SQL, ma in questo caso i dati non provengono da un'origine SQL, quindi ho bisogno di fare il join in codice ... ma come ho detto ho i 2 set di risultati, e Linq to Objects può fare un join ... (e più tardi la proiezione) sarebbe davvero bello semplicemente sostituire le costanti di espressione MyProv.Table<Customer> e MyProv.Table<Order> con List<Customer> e List<Order> e lascia che un provider List<> esegua l'espressione ... è possibile? Come?

Risposta accettata

Il tipo di cosa che cercavo sostituiva la costante Queryable <> nella struttura dell'espressione con un set di risultati IEnumerable (o IQueryable via .AsQueryable ()) concreto ... questo è un argomento complesso che probabilmente ha senso solo per Linq Scrittori di provider che sono al ginocchio nel visitatore di espressioni ecc.

Ho trovato uno snippet sulla procedura dettagliata di msdn che fa qualcosa di simile a quello che sto cercando, questo mi dà una via da seguire ...

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;
        }
    }
}

Risposta popolare

Entrambe le risposte precedenti funzionano, ma si legge meglio se si utilizza AsEnumerable () per eseguire il cast di IQueryable in IEnumerable:

// 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 });

MODIFICARE:

// ... 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


Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché