Performing part of a IQueryable query and deferring the rest to Linq for Objects

前端 未结 5 1029
温柔的废话
温柔的废话 2021-02-15 15:37

I have a Linq provider that sucessfully goes and gets data from my chosen datasource, but what I would like to do now that I have my filtered resultset, is allow Linq to Objects

相关标签:
5条回答
  • 2021-02-15 15:46

    If you implemented a Repository Pattern you could get away with just providing an IQueryable back and abstract away the table.

    Example:

    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
              }
    

    and then just build your provider to model the IQueryable pattern in your Repository method just like this article illustrates.

    This way, you can write all kinds of providers to use for whatever you need. You can have a LINQ 2 SQL provider, or write an in memory provider for your unit tests.

    The Repository method for the LINQ 2 SQL provider would look something like this:

    public IQueryable<T> Repository<T>() where T : class
    {
        ITable table = _context.GetTable(typeof(T));
        return table.Cast<T>();
    }
    
    0 讨论(0)
  • 2021-02-15 15:48

    Both of the previous answers work, but it reads better if you use AsEnumerable() to cast the IQueryable to 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 });
    

    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
    
    0 讨论(0)
  • 2021-02-15 15:50

    Unless I'm misunderstanding, I generally just add .ToArray() in the chain of linq methods at the point where I want the linq provider to execute.

    For example (think 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 through OrderBy() gets translated into SQL, but the Select() is LINQ to Objects.

    0 讨论(0)
  • 2021-02-15 15:53

    Rob's answer is good, but forces full enumeration. You could cast to keep extension method syntax and lazy evaluation:

    var res = ((IEnumerable<Foo>)dc.Foos
                .Where(x => x.Bla > 0))  // IQueryable
              .Where(y => y.Snag > 0)   // IEnumerable
    
    0 讨论(0)
  • 2021-02-15 15:56

    The kind of thing that I was after was replacing the Queryable<> constant in the expression tree with a concrete IEnumerable (or IQueryable via .AsQueryable()) result set...this is a complex topic that probably only makes any sense to Linq Provider writers who are knee deep in expression tree visitors etc.

    I found a snippet on the msdn walkthrough that does something like what I am after, this gives me a way forward...

    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;
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题