我对实体框架模型有一些疑问,并试图巧妙地整理我的查询。
我已经有了一个通用存储库。
这是我尝试做的事情的关键 - 它不起作用,但我不确定为什么以及如何解决它。
代码中的第二个功能有效,但第一个问题还有几个 - 我已经将它包括在内,以便您可以了解我尝试做的事情。
IEnumerable<Product> QueryLive(Expression<Func<Product, bool>> predicate)
{
var exp = new Expression<Func<Product, bool>>(x => x.IsLive);
var combined = Expression.AndAlso(exp, predicate);
return QueryPublished(combined);
}
IEnumerable<Product> QueryPublished(Expression<Func<Product, bool>> predicate)
{
using (var uow = new UnitOfWork(Connections.ProductComparision))
{
var r = new Repository<Product>(uow.Context);
return r.Find(predicate).ToList();
}
}
我收到2个语法错误:
行:var exp =&#39; System.Linq.Expressions.Expression&#39;不包含带有1个参数的构造函数
返回:&#39;合并&#39; var是二进制表达式,与QueryPublished()的参数要求冲突。
答案 0 :(得分:1)
以下是我在您的代码中看到的一些问题:
var exp = new Expression<Func<Product, bool>>(x => x.IsLive);
无法编译,定义表达式,只需使用以下语法:
Expression<Func<Product, bool>> exp = x => x.IsLive;
combined
的类型为Expression
,QueryPublished
期望参数类型为Expression<Func<Product, bool>>
。这也不会编译。
predicate
中的参数(例如x
中的x =>
)与lambda参数exp
不同,因此您不能简单地将它们组合在一起方式。
您可以使用LinqKit轻松地组合表达式,如下所示:
IEnumerable<Product> QueryLive(Expression<Func<Product, bool>> predicate)
{
Expression<Func<Product, bool>> exp = x => x.IsLive;
Expression<Func<Product, bool>> combined = x => exp.Invoke(x) && predicate.Invoke(x);
return QueryPublished(combined.Expand());
}
答案 1 :(得分:0)
<强>第一强>:
更改
var exp = new Expression<Func<Product, bool>>(x => x.IsLive);
要
Expression<Func<Product, bool>> exp = x => x.IsLive;
<强>第二强>:
更改
var combined = Expression.AndAlso(exp, predicate);
要
var combined = Expression.Lambda<Func<Product, bool>>(Expression.AndAlso(exp.Body, predicate.Body), exp.Parameters);
答案 2 :(得分:0)
大多数Expression
类方法用于构建表达式树(例如lambda表达式Body
,不能直接用于组合lambda表达式。
为了在你的情况下组合所谓的谓词表达式(Expression<Func<T, bool>>
),人们通常会使用一些自定义帮助扩展方法,称为谓词构建器。最着名的是来自LinqKit的PredicateBuilder
,但它与EF不兼容,需要来自包的Expand
/ AsExpandable`服务。我个人使用我自己的,Applying LINQ filters based on a multi-dimensional array和Establish a link between two lists in linq to entities where clause,Gert Arnold的评论中指出的与universal PredicateBuilder非常相似。两者都产生EF兼容表达式,这是我的:
public static class PredicateUtils
{
sealed class Predicate<T>
{
public static readonly Expression<Func<T, bool>> True = item => true;
public static readonly Expression<Func<T, bool>> False = item => false;
}
public static Expression<Func<T, bool>> Null<T>() { return null; }
public static Expression<Func<T, bool>> True<T>() { return Predicate<T>.True; }
public static Expression<Func<T, bool>> False<T>() { return Predicate<T>.False; }
public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right)
{
if (Equals(left, right)) return left;
if (left == null || Equals(left, True<T>())) return right;
if (right == null || Equals(right, True<T>())) return left;
if (Equals(left, False<T>()) || Equals(right, False<T>())) return False<T>();
var body = Expression.AndAlso(left.Body, right.Body.Replace(right.Parameters[0], left.Parameters[0]));
return Expression.Lambda<Func<T, bool>>(body, left.Parameters);
}
public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> left, Expression<Func<T, bool>> right)
{
if (Equals(left, right)) return left;
if (left == null || Equals(left, False<T>())) return right;
if (right == null || Equals(right, False<T>())) return left;
if (Equals(left, True<T>()) || Equals(right, True<T>())) return True<T>();
var body = Expression.OrElse(left.Body, right.Body.Replace(right.Parameters[0], left.Parameters[0]));
return Expression.Lambda<Func<T, bool>>(body, left.Parameters);
}
static Expression Replace(this Expression expression, Expression source, Expression target)
{
return new ExpressionReplacer { Source = source, Target = target }.Visit(expression);
}
class ExpressionReplacer : ExpressionVisitor
{
public Expression Source;
public Expression Target;
public override Expression Visit(Expression node)
{
return node == Source ? Target : base.Visit(node);
}
}
}
一旦你有这样的帮助者,所讨论的方法很简单:
IEnumerable<Product> QueryLive(Expression<Func<Product, bool>> predicate)
{
return QueryPublished(predicate.And(x => x.IsLive));
}