将linq树表达式执行到where

时间:2014-01-24 09:38:15

标签: c# linq entity-framework expression-trees

这是我的方案:我需要使用对链接实体中的属性的“OR”查询从实体中提取数据。

这些是我的实体:

public class Dealer
{
  public virtual int id{get;set;}
  public virtual string name{get;set;}
  public virtual IList<Car> Cars{get;set;}
}

public class Car 
{
  public virtual int id{get;set;}
  public virtual string name{get;set;}
  public virtual int kw{get;set;}
}

示例:我想提取所有拥有98kw或100kw汽车的经销商。 Sql示例:

SELECT Dealers.* FROM Dealers INNER JOIN Cars ON Cars.IdDealer = Dealers.Id WHERE Cars.kw = 98 OR Cars.kw = 100

我尝试使用Expression树,但我不知道如何使用它们。 我试过这个:

var dealers = Session.Linq<Dealers>();
ParameterExpression pe = Expression.Parameter(typeof(int), "kw");
Expression tot = null;
var powers = new int[2]{98, 100};

for (var i = 0; i < powers.Length; i++)
{
    Expression right = Expression.Constant(int.Parse(powers[i]));
    if (i > 0)
        tot = Expression.Or(tot, Expression.Equal(pe, right));
    else
        tot = Expression.Equal(pe, right);
}
dealers = dealers.Where(x => x.Cars.Any(Expression.Lambda<Func<Cars, bool>>(tot, null)));

但是我在尝试执行Expression的最后一行得到了这些编译器错误:

  • 无法将lambda表达式转换为string类型,因为它不是委托类型
  • System.Collections.Generic.IList<Cars>不包含Any的定义和最佳扩展方法重载System.Linq.Enumerable.Any(System.Collections.Generic.IEnumerable,System.Func)有一些无效的参数< / LI>
  • 参数2:无法从System.Linq.Expressions.Expression<System.Func<Cars,bool>>转换为System.Func<Cars,bool>

有什么建议吗?

3 个答案:

答案 0 :(得分:2)

根据我留下的评论:

...我可以提出一些建议,可能会或可能不会受到欢迎。在我看来,你应该避免在开放环境中以这种方式使用RAW表达式。我衷心地建议你采用一种更封闭的方法,看看像albahari谓词建构者这样的东西:albahari.com/nutshell/predicatebuilder.aspx会为你节省很多挫折感。页面上也有一些很好的工作示例

我无法强调这给我们承担的许多项目带来的好处。此库/方法的用法转换为以下行的表达式:

IQueryable<Product> SearchProducts (params string[] keywords)
{
  var predicate = PredicateBuilder.False<Product>();

  foreach (string keyword in keywords)
  {
    string temp = keyword;
    predicate = predicate.Or (p => p.Description.Contains (temp));
  }
  return dataContext.Products.Where (predicate);
}

等。因此,您可以构建相当复杂的语句将所有内部隐藏起来。这是完全合理的,特别是如果您现在或将来可能有更多的初级开发人员处理代码。我强烈建议你放纵自己的好奇心,徘徊在链接上,从那里获得更好的感受。

答案 1 :(得分:1)

尝试像这样更改你的代码

var dealers = Session.Linq<Dealers>();
ParameterExpression pe = Expression.Parameter(typeof(Car), "c");
var kw = Expression.Property(pe, "kw");
var powers = new string[2]{"98", "100"};

Expression tot = powers.Select(p=>Expression.Constant(int.Parse(p)))
                       .Select(p=>Expression.Equal(kw,p))
                       .Aggregate((a,b)=>Expresion.Or(a,b));

您还需要将Cars声明更改为IEnumerable<Car>IQueriable<Car>

如果 IEnumerable<Car> ,则将其称为

dealers = dealers.Where(x => x.Cars.Any(Expression.Lambda<Func<Cars, bool>>(tot, pe).Compile()));

如果 IQueriable<Car> ,则将其称为

dealers = dealers.Where(x => x.Cars.Any(Expression.Lambda<Func<Cars, bool>>(tot, pe)));

答案 2 :(得分:0)

将Expression.Lambda的结果转换为

Expression<Func<Car, bool>>

你需要传递参数表达式:

x.Cars.Any( ( Expression<Func<Car, bool>> )Expression.Lambda<Func<Cars, bool>>( tot, pe ) )