LINQ to Entities 无法识别方法“布尔包含 [Int32]
Posted
技术标签:
【中文标题】LINQ to Entities 无法识别方法“布尔包含 [Int32]【英文标题】:LINQ to Entities does not recognize the method 'Boolean Contains[Int32] 【发布时间】:2013-05-23 15:42:28 【问题描述】:我使用以下扩展方法在 LINQ-To-Entities 上执行包含:
public static class Extensions
public static IQueryable<TEntity> WhereIn<TEntity, TValue>
(
this ObjectQuery<TEntity> query,
Expression<Func<TEntity, TValue>> selector,
IEnumerable<TValue> collection
)
if (selector == null) throw new ArgumentNullException("selector");
if (collection == null) throw new ArgumentNullException("collection");
if (!collection.Any())
return query.Where(t => false);
ParameterExpression p = selector.Parameters.Single();
IEnumerable<Expression> equals = collection.Select(value =>
(Expression)Expression.Equal(selector.Body,
Expression.Constant(value, typeof(TValue))));
Expression body = equals.Aggregate((accumulate, equal) =>
Expression.Or(accumulate, equal));
return query.Where(Expression.Lambda<Func<TEntity, bool>>(body, p));
//Optional - to allow static collection:
public static IQueryable<TEntity> WhereIn<TEntity, TValue>
(
this ObjectQuery<TEntity> query,
Expression<Func<TEntity, TValue>> selector,
params TValue[] collection
)
return WhereIn(query, selector, (IEnumerable<TValue>)collection);
当我调用扩展方法来检查 id 列表是否在特定表中时,它可以正常工作,并且我会返回 id 列表,如下所示:
List<int> Ids = _context.Persons
.WhereIn(x => x.PersonId, PersonIds)
.Select(x => x.HeaderId).ToList();
当我执行下一条语句时,它抱怨 LINQ-To-Entities 无法识别 Contains(int32),但我认为我不再反对实体,而是反对整数的集合。
predicate = predicate.And(x=> Ids.Contains(x.HeaderId));
如果我有一个逗号分隔的字符串,例如“1,2,3”,那么以下工作:
predicate = predicate.And(x=>x.Ids.Contains(x.HeaderId));
我正在尝试获取返回的列表并创建逗号分隔的字符串列表,这里的问题是,现在当我执行predicate = predicate.And(x=>sb.Contains(x.HeaderId.ToString());
时,它抱怨它不喜欢 ToString()。
我也试过这样做:
predicate = predicate.And(x=>Extensions.WhereIn(Ids, x.id));, but it can't resolve WhereIn. It says I must add `<>`, but I am not sure what to add here and how implement it.
【问题讨论】:
代码格式化了一点。 “谓词”从何而来?它是 IQueryable 吗? @SamBauwens - albahari.com/nutshell/predicatebuilder.aspx 为什么要显示 WhereIn 扩展方法?如果 Ids 真的是List<int>
,我们不介意你是如何得到它的。问题似乎来自 PredicateBuilder(猜你用这个)
@Xaisoft:你已经回答了你自己的问题。 .NET3.5 中的 EF 不支持IEnumerable<T>.Contains
。就是这样。
【参考方案1】:
你的 WhereIn 没有错,你是对的:当你使用 Ids 时,你不再反对实体,而是一个整数集合。
问题是当您在谓词上使用 .And 时:LINQ-To-Entities 尝试将这些括号内的 everything 转换为 Entities 方法,但没有对应的包含方法。
解决方案:
代替
predicate = predicate.And(x=> Ids.Contains(x.HeaderId));
使用
predicate = predicate.And(Contains<XClassName, int>(x.HeaderId));
其中包含定义如下:
private static Expression<Func<TElement, bool>> Contains<TElement, TValue>(Expression<Func<TElement, TValue>> valueSelector, List<TValue> values)
if (null == valueSelector) throw new ArgumentNullException("valueSelector");
if (null == values) throw new ArgumentNullException("values");
if (!values.Any())
return e => false;
var equals = values.Select(value => (Expression)Expression.Equal(valueSelector.Body, Expression.Constant(value, typeof(TValue))));
return Expression.Lambda<Func<TElement, bool>>(@equals.Aggregate(Expression.Or), valueSelector.Parameters.Single());
而 XClassName 是您的 x
的类的名称【讨论】:
【参考方案2】:你不能像那样使用数组,你需要预先访问这个 lambda 以将其扩展为基元。或者,您可以更改底层提供程序,使其知道如何生成 IN 语句,因为默认情况下它不会。
没有找到一个人实际实施它的帖子,一旦我这样做了就会更新。
基本上当你使用你的扩展方法时,就像
x=>arr.Contains(x)
因此,如果您尝试对实体集等执行此类 lambda,它会抛出异常,说明参数只能是原语。
原因是底层提供者不知道如何将 .Contains 数组作为函数参数的方法转换为 sql 查询。为了解决这个问题,你有两个选择
教它如何使用T[]作为参数并使用包含这个参数
更新您的扩展方法以生成将使用“允许”构建块的新 lamda,即使用原始类型(如 int、string、guid 等)的表达式。
查看这篇文章
http://msdn.microsoft.com/en-us/library/bb882521(v=vs.90).aspx
【讨论】:
你能用一个例子来扩展你的答案吗?我还是有点迷茫。【参考方案3】:替换你的:
List<int> Ids = _context.Persons
.WhereIn(x => x.PersonId, PersonIds)
.Select(x => x.HeaderId).ToList();
与
var Ids = _context.Persons
.WhereIn(x => x.PersonId, PersonIds)
.Select(x => x.HeaderId).ToList();
然后尝试。
【讨论】:
以上是关于LINQ to Entities 无法识别方法“布尔包含 [Int32]的主要内容,如果未能解决你的问题,请参考以下文章
LINQ to Entities 无法识别方法 IsNullOrWhiteSpace
错误:LINQ to Entities 无法识别方法 DataLength
LINQ To Entities 无法识别方法 Last。真的吗?
LINQ To Entities 无法识别方法 Last。真的吗?