【问题标题】:combine two expressions结合两个表达式
【发布时间】:2011-05-02 09:54:03
【问题描述】:

我正在尝试创建一个在实体框架查询中使用的表达式。 我创建了两个表达式:

public Expression<Func<IEntityPriceDefinition, bool>> IsMatchExpression(long additionId)
    {
        return x => x.PriceDefinition.AdditionsPrices.Any(a => a.AdditionId == additionId);
    }
public Expression<Func<IEntityPriceDefinition, bool>> IsMatchExpression(
    long? inviterId, long? routeId, long? luggageTypeId)
{
    return x =>
        (inviterId.HasValue || routeId.HasValue || luggageTypeId.HasValue) &&
        !(
            (x.PriceDefinition.InviterId.HasValue && inviterId.HasValue &&
                PriceDefinition.InviterId.Value != inviterId.Value) ||

            (PriceDefinition.LuggageTypeId.HasValue && luggageTypeId.HasValue &&
                PriceDefinition.LuggageTypeId.Value != luggageTypeId.Value) ||

            (PriceDefinition.InviterId.HasValue && inviterId.HasValue &&
                PriceDefinition.InviterId.Value != inviterId.Value)
        );
}

现在我愿意将它们结合起来:

    public Expression<Func<IEntityPriceDefinition, bool>> IsMatchExpression(
        long? inviterId, long? routeId, long? luggageTypeId, long additionId)
    {
        return IsMatchExpression(inviterId, routeId, luggageTypeId) &&
                IsMatchExpression(additionId);
    }

此方法无法编译。我也觉得我做错了什么。我该如何解决?

编辑:
我忘记了重要的部分!问题已更新。

【问题讨论】:

  • @Nicolas78:我需要创建将两个表达式结合起来的表达式。
  • 啊好的。好吧,您在这里写的内容会评估这两个表达式,并根据是否满足两者来尝试返回真或假。也许您可以谈谈这些 MatchExpressions 和您的用例,以便我们更好地帮助您。
  • @Nicolas78:你说得对 - 我忘记了重要的事情,我解决了这个问题。

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


【解决方案1】:

您必须直接使用表达式组件来执行此操作。

public Expression<Func<IEntityPriceDefinition, bool>> IsMatchExpression(
        long? inviterId, long? routeId, long? luggageTypeId, long additionId)
{
    var a = IsMatchExpression(inviterId, routeId, luggageTypeId);
    var b = IsMatchExpression(additionId);
    var p = Expression.Parameter(typeof(IEntityPriceDefinition),"x");
    var c = Expression.AndAlso(Expression.Invoke(a,p),Expression.Invoke(b,p));
    var r = Expression.Lambda<Func<IEntityPriceDefinition, bool>>(c,p);
    return r;
}

通过从两个表达式中的每一个中拆分.Body 并用新参数替换(使用ExpressionVisitor)参数,这可以变得更加复杂;并且您的两种工作方法中的每一种都可以更改以将它们的参数绑定到ConstantExpressions,从而完全失去 lambda 表达式语法。实际上,这些更改可能对于制作可以与实体框架正常工作的表达式是必要的,但这需要一些时间才能让我在答案中发布。

另见How can I compose an Entity Framework query from smaller, resusable queries?

【讨论】:

  • 它创建了一个异常:'System.Func`2[IEntityPriceDefinition,System.Boolean]' 类型的表达式不能用于返回类型'System.Boolean'。
  • 它试图从中生成 lambda:var r = Expression.Lambda>(c,p);
  • 同时我标记了一个答案。如果你有一个想法 - 我会在这里听。谢谢!
  • @Naor:我终于有时间看这个了,没有报错。您是否更改了方法中的某些内容?
【解决方案2】:

好的,会不会是这样的

var x = IsMatchExpression(inviterId, routeId, luggageTypeId)
var y = IsMatchExpression(additionId);
return arg => x(arg) && y(arg) 

?

【讨论】:

  • 你可能需要一些额外的语法巫术,我不熟悉表达式接口;然而,关键是在函数中调用这些函数与返回一个 lambda 函数之间的区别,后者将在稍后调用返回值
  • 这不起作用。我相信我使用了错误的 Expression 界面。我不确定这是为实体框架查询创建表达式的方式。
  • 在这一行:“return arg => x(arg) && y(arg);”我得到“x 是一个变量,但像一个方法一样使用”。我相信这不是方法,我需要构建一个表达式树,但我不知道如何开始。
【解决方案3】:

刚刚创建的组合方法:

   public Expression<Func<IEntityPriceDefinition, bool>> IsMatchExpression(
        long? inviterId, long? routeId, long? luggageTypeId, long additionId)
    {
    return x =>
        (inviterId.HasValue || routeId.HasValue || luggageTypeId.HasValue) &&
        (x.PriceDefinition.AdditionsPrices.Any(a => a.AdditionId == additionId)) &&
        !(
            (x.PriceDefinition.InviterId.HasValue && inviterId.HasValue &&
                PriceDefinition.InviterId.Value != inviterId.Value) ||

            (PriceDefinition.LuggageTypeId.HasValue && luggageTypeId.HasValue &&
                PriceDefinition.LuggageTypeId.Value != luggageTypeId.Value) ||

            (PriceDefinition.InviterId.HasValue && inviterId.HasValue &&
                PriceDefinition.InviterId.Value != inviterId.Value)
        );
}

不是最好的解决方案,但它有效。

【讨论】:

    猜你喜欢
    • 2015-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-23
    • 2012-03-14
    相关资源
    最近更新 更多