【发布时间】:2013-07-18 12:11:08
【问题描述】:
假设Type 的数组作为标准对象,它指示必须显示的子类型。
型号:
public abstract class Shape { }
public class Circle : Shape { }
public class Rectangle : Shape { }
我已经实现了一个应用这种查询的扩展方法
public static IQueryable<TSource> OfTypes<TSource, TResult>(
this IQueryable<TSource> source,
Expression<Func<TSource, TResult>> expression,
params Type[] types)
{
if (!types.Any())
{
return source;
}
Expression finalExpression = Expression.TypeIs(expression, types.First());
foreach (var type in types.Skip(1))
{
finalExpression = Expression.OrElse(
Expression.TypeIs(expression, type),
finalExpression);
}
var lambdaExpression = Expression.Lambda<Func<TSource, bool>>(
finalExpression,
expression.Parameters);
return source.Where(lambdaExpression);
}
那我就可以这样用了
var types = new Type[] { typeof(Circle), typeof(Rectange) };
db.Shapres.OfTypes(s => s, types);
生成的表达式类似于
e => e is Circle || e is Rectange
正是我想要的,但我得到了这个错误
LINQ to Entities 不支持 LINQ 表达式节点类型“Lambda”。
即使我在扩展方法的最后一行使用了LinqKit 的AsExpandable() 方法:
return source.AsExpandable().Where(lambdaExpression);
但同样的错误。
我也试过 PredicateBuilder 这样但又出现同样的错误
var finalExpression = PredicateBuilder.False<TSource>();
foreach (var type in types)
{
var expressionParameter = Expression.Parameter(typeof(TSource), "it");
var lambdaExpression = Expression.Lambda<Func<TSource, bool>>(
Expression.TypeIs(expression, type),
expressionParameter);
finalExpression.Or(lambdaExpression);
}
有什么问题?
如何在 EF 中毫无问题地将 Expression 转换为 Expression<Func<T, TResult>>?
或者如何将Expression 实例传递给Where 扩展方法?
或者我如何将Expression.TypeIs 用于 EF?
【问题讨论】:
-
if (!types.Any())可能会导致NullReferenceException。 -
@Steve - 这不是我的问题。
-
我知道,只是指出来。
-
我可以帮忙,但请注意,您的示例可以在没有 Linq.Expression 命名空间的情况下完成。
-
哦...我现在明白了...但不确定 EF 是否可以工作。但是,它非常简单。您实际上想使用
Expression finalExpression = Expression.TypeIs(expression.Body, types.First());。注意.Body。我花了几个小时来解决这个问题,使用 LinqPad 弄清楚如何做动态 Linq。您可能会发现还需要换掉ParameterExpression的每个实例。另外,在数据库之前对数组进行尝试。 LinqToObjects 编译器比 LinqToEF 编译器更强大,有效的 Linq 可能无法在 EF 上编译。
标签: c# linq entity-framework ef-code-first