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

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

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

有任何想法吗?

编辑:这里有一些很好的答案,但给出的forms……

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

在我的提供者中,我可以轻松地从客户和订单中获取2个结果集,如果数据来自SQL源,我将构建并传递SQL Join语法,但是这种情况下数据不是来自SQL源,所以我需要在代码中进行连接…但正如我所说,我有2个结果集,而Linq to Objects可以进行连接……(以及后来的投影)只需替换表达式常量MyProv.TableMyProv.Table with ListList ,让List提供程序处理表达式……这可能吗? 怎么样?

以前的两个答案都有效,但如果你使用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 }); 

编辑:

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

我所追求的是用一个具体的IEnumerable(或IQueryable via .AsQueryable())结果集替换表达式树中的Queryable <>常量……这是一个复杂的主题,可能只对Linq有意义表达树访问者等膝盖深处的提供者作家

我在msdn演练中找到了一个片段,它做了我喜欢的事情,这给了我一条前进的道路……

 using System; using System.Linq; using System.Linq.Expressions; namespace LinqToTerraServerProvider { internal class ExpressionTreeModifier : ExpressionVisitor { private IQueryable queryablePlaces; internal ExpressionTreeModifier(IQueryable 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)) return Expression.Constant(this.queryablePlaces); else return c; } } } 

如果您实现了一个存储库模式,那么只需提供一个IQueryable返回并抽象出该表即可。

例:

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

然后构建您的提供程序以在Repository方法中建模IQueryable模式,就像本文所示。

这样,您可以编写各种提供程序以用于您需要的任何内容。 您可以拥有LINQ 2 SQL提供程序,也可以为内存提供程序编写unit testing。

LINQ 2 SQL提供程序的Repository方法如下所示:

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

除非我误解,否则我通常只在linq方法链中添加.ToArray(),我想要linq提供程序执行。

例如(想想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}); 

因此,通过OrderBy()被转换为SQL,但Select()是LINQ to Objects。

Rob的答案很好,但强制完整列举。 您可以强制转换以保持扩展方法语法和延迟评估:

 var res = ((IEnumerable)dc.Foos .Where(x => x.Bla > 0)) // IQueryable .Where(y => y.Snag > 0) // IEnumerable