【问题标题】:How can I create a dynamic select expression in LINQ?如何在 LINQ 中创建动态选择表达式?
【发布时间】:2011-03-16 22:15:51
【问题描述】:

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

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 中,但似乎出现了同样的问题。

那么问题来了,如何避免复制粘贴呢?

【问题讨论】:

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


    【解决方案1】:

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

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

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

    干杯...

    【讨论】:

    • 这种方式将意味着整个表达式将被转换为sql,userLikesBananas将被传入。我正在寻找一种方式,意味着在将表达式转换为sql之前对其进行调整。使用 if 语句会产生更清晰的查询,但这是个好主意,谢谢。
    【解决方案2】:

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

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

    有(一个小菜鸟般的)技巧可以解决这个问题(我正在使用它并且它的工作原理):

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

      公共枚举 MyAtrs{ID, FirstName, Surname}

    2. 为条件创建Dictionary&lt;MyAtrs,bool&gt;(并填写)(如果您想获取此属性,请设置true

      公共词典 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=>new { ID = Dic[MyAtrs.ID] ? e.dbID:0, 名字 = Dic[MyAtrs.Firstname] ? e.dbFirstname:空, 姓氏 = Dic[MyAtrs.Surname] ? e.db姓:空, });

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

    【讨论】:

      猜你喜欢
      • 2014-06-16
      • 1970-01-01
      • 2016-12-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-11
      • 2014-07-06
      • 1970-01-01
      相关资源
      最近更新 更多