如何在LINQ中创建动态选择表达式?

时间:2010-07-16 11:58:13

标签: c# linq linq-to-sql dynamic

我目前看起来有点像这样:

if(userLikesBananas)
{
    return from fruit in basket
           select new Fruit
           {
               AteBanana = Bowl.Any(b => b.OwnedBy == user && b.Contains(fruit) && fruit.Type == FruitType.Banana),
               ...
               ...
               //lots of properties
               ...
           }
}
else
{
    return from fruit in basket
           select new Fruit
           {
               AteBanana = Bowl.Any(b => b.Contains(fruit)),
               ...
               ...
               //lots of properties
               ...
           }
}

不可否认,这个例子绝对没有意义,但原则是我想根据任意标准改变属性选择的条件。现在重复选择语句。

现在我需要添加一个依赖于标准的时间了。我不希望有4种不同的情况,其中物业条件略有不同。

我想做的是这样的事情:

Func<Fruit, bool> fruitFunc = f => false;

if(userLikesBananas)
{
    fruitFunc = f => Bowl.Any(b => b.OwnedBy == user && b.Contains(f) && f.Type == FruitType.Banana);
}
else
{
    fruitFunc = f => Bowl.Any(b => b.Contains(f));
}

return from fruit in basket
       select new Fruit
       {
           AteBanana = fruitFunc(fruit)
           ...
           ...
           //lots of properties
           ...
       };

麻烦的是表达式无法转换为sql,因为它包含动态调用。我尝试将Func包裹在Expression中,但似乎也出现了同样的问题。

所以问题是,如何避免复制和粘贴?

2 个答案:

答案 0 :(得分:3)

...我的英语不好,但我会尝试解释如何轻松解决这个问题: - )

动态Linq不适合类型控制 - 它易于使用,但您无法浏览生成的对象(x.Name,x.Surname等)

有一个(一个类似litle noob的)技巧来解决这个问题(我正在使用它并且它的工作很费劲):

  1. 使用您选择的对象的属性创建enum

    public enum MyAtrs {ID,FirstName,Surname}

  2. 创建Dictionary<MyAtrs,bool>(并填写)条件(如果您想获得此属性,请设置true

    public Dictionary Dic = new Dictionary(); Dic.Add(MyAtrs.ID,TRUE); Dic.Add(MyAtrs.Firstname,FALSE); Dic.Add(MyAtrs.Surname,TRUE);

  3. 建立您的查询:

    var query = DBContext.MyDBTable.Where(predicate).Select(e =&gt; new { ID = Dic [MyAtrs.ID]? e.dbID:0, Firstname = Dic [MyAtrs.Firstname]? e.dbFirstname:空, 姓氏= Dic [MyAtrs.Surname]? e.dbSurname:空, });

  4. 在这种情况下,SQL Select语句中将有所有3列,但它只是几个字节(重要的是......)。 SQL Server会返回所有3列,但(在这种情况下)Firstname将为空(类似于{ID = 123,Firstname =,Surname =“Jobs”})。 它并不精彩但是如何在不失去类型控制的情况下构建“动态”选择表达式的简单方法:)

答案 1 :(得分:0)

我可以建议以不同的方式编写Func(可能是这样的):

fruitFunc = f => Bowl.Any(b => ((f.Type == FruitType.Banana && b.OwnedBy == user && userLikesBananas) || !userLikesBananas) && b.Contains(f));

我没有测试它是否有效,但这可能是一种编写函数以覆盖更多情况的方法(不仅仅是2)。这个方法在某种程度上类似于我记得的布尔代数......

干杯...