执行IQueryable查询的一部分并将其余部分推迟到Linq for Objects

Tim*_*vis 8 c# linq iqueryable expression-trees

我有一个Linq提供程序成功地从我选择的数据源获取数据,但是我现在想要做的是我有我的过滤结果集,允许Linq to Objects处理Expression树的其余部分(对于像Joins这样的东西,投影等)

我的想法是我可以通过ExpressionVisitor将结果集IEnumerable替换为包含我的IQueryProvider的表达式常量,然后返回该新表达式.还从我的IQueryable返回IEnumerable的提供程序......但这似乎不起作用:-(

有任何想法吗?

编辑:这里有一些好的答案,但给出了表格......

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
          }
Run Code Online (Sandbox Code Playgroud)

在我的提供程序中,我可以轻松地从客户和订单中获取2个结果集,如果数据来自SQL源,我将构建并传递SQL Join语法,但是这种情况下数据不是来自SQL源,所以我需要做的代码中加入...但我说我有2分结果集,和LINQ到对象可以做一个连接...(以及后来的投影)这将是真正的好,只是代替表达常数MyProv.Table<Customer>MyProv.Table<Order>List<Customer>List<Order>让一个List<>提供者处理表达式......这可能吗?怎么样?

Luc*_*cas 6

以前的两个答案都有效,但如果你使用AsEnumerable()将IQueryable强制转换为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 });
Run Code Online (Sandbox Code Playgroud)

编辑:

// ... 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
Run Code Online (Sandbox Code Playgroud)


Tim*_*vis 3

我所追求的是将表达式树中的 Queryable<> 常量替换为具体的 IEnumerable (或通过 .AsQueryable() 实现 IQueryable)结果集...这是一个复杂的主题,可能只对 Linq 有意义深陷表达式树访问者等的提供者作者。

我在 msdn 演练中发现了一个片段,它的作用类似于我所追求的,这给了我前进的方向......

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;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)