LINQ to Entities无法识别方法'Boolean Contains [Int32]

时间:2013-05-28 15:32:09

标签: c# entity-framework linq-to-entities

我有以下扩展方法,用于在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);
        }
  }

当我调用extenion方法检查id列表是否在特定表中时,它可以正常工作,我会返回ID列表,如下所示:

List<int> Ids = _context.Persons
                        .WhereIn(x => x.PersonId, PersonIds)
                        .Select(x => x.HeaderId).ToList();

当我执行下一个语句时,它抱怨LINQ-To-Entities没有识别Contains(int32),但我认为我不再反对该实体,而是一组int。

predicate = predicate.And(x=> Ids.Contains(x.HeaderId));

如果我有逗号分隔的字符串,例如“1,2,3”,那么以下工作:

predicate = predicate.And(x=>x.Ids.Contains(x.HeaderId));

我正在尝试将List返回并创建逗号分隔的字符串列表,这里的问题是,当我执行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.

3 个答案:

答案 0 :(得分:0)

WhereIn 在哪里没有错,而且你是对的:当你使用 ID 时,你不再反对该实体,而是一组整数。

问题是当你在谓词上使用 .And 时:LINQ-To-Entities尝试将这些括号内的所有转换为Entities方法,并且没有相应的包含方法。

解决方案:

而不是

predicate = predicate.And(x=> Ids.Contains(x.HeaderId));

使用

predicate = predicate.And(Contains<XClassName, int>(x.HeaderId));

其中Contains的定义如下:

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

的类的名称

答案 1 :(得分:-1)

你不能使用这样的数组,你需要预先检查这个lambda,以便将它扩展为基元。或者,您可以更改基础提供程序,以便它知道如何生成IN语句,因为它默认情况下不会。

没有找到一个人真正实现它的帖子,一旦我做了就会更新。

基本上,当您使用扩展方法时,它就像

x=>arr.Contains(x)

因此,如果你尝试再次执行这样的lambda你的实体集等,它会抛出异常,说参数只能是原语。

原因是底层提供程序不知道如何将数组的.Contains方法作为函数参数转换为sql查询。并且为了解决你有两个选择

  • 教它如何使用T []作为参数并使用包含此参数的

  • 更新你的扩展方法,以便生成新的lamda,它将使用'allowed'构建块,即使用int,string,guid等原始类型的表达式。

查看这篇文章

http://msdn.microsoft.com/en-us/library/bb882521(v=vs.90).aspx

答案 2 :(得分:-2)

替换你的:

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();

然后尝试。