1

我正在使用实体框架来处理 MVC 应用程序中的数据库:我使用启动表单中的多个字段为应用程序创建了一个搜索引擎,并设置了来自用户角色的权限,因此创建 select 语句的例程正在增长,所以有时我会遇到这种情况。在我做出选择之前:

  1. var orders = db.Orders.Where(ord => ord.Channel == 1 || ord.Channel == 2);

    在源代码中,在某些情况下,用户类型、过滤器组合等,我必须更改此过滤器或删除此条件

  2. 订单 = db.Orders.Where( ord => ord.Channel == 1 );

    这只是一个简单的例子,因为这样做我会丢失我在 Linq 表达式树中完成的其他过滤器,并导致我经常要求添加功能,因此很难重新组织所有代码以测试所有先决条件向表达式树添加条件,所以我想知道是否可以在 linq 表达式树中添加语句之后和在 sql 查询中解析和转换树之前删除语句

卢卡

4

1 回答 1

1

假设我正确理解了您的问题,我相信最简单的方法是推迟创建查询,直到您收集了知道查询应该是什么样子所需的所有数据,即在这种情况下,这意味着您只构建查询在您已经知道是否确实需要应用该条件之后。

如果您无法推迟创建查询(在我看来这就是您要说的),但您仍然可以预见到以后可能需要删除哪些条件,我会考虑引入一个布尔值查询中的哨兵,例如基于您的查询片段:

var orders = db.Orders.Where( ord => 
    (isFirstConditionRelevant && ord.Channel == 1) 
    || (isSecondConditionRelvant && ord.Channel == 2));

变量 'isFirstConditionRelevant' 和 'isSecondConditionRelevant' 最初将设置为 true 并由查询表达式捕获,但如果您需要相应的条件,您可以稍后(例如,在执行查询之前)设置为 false没有效果。请注意,使用这种方法,查询的 SQL 翻译仍将包含条件,但它还将包含每个哨兵的参数,当服务器执行查询时,该参数将短路布尔逻辑。

另请注意,条件中的任何常量(例如,'ord.Channel == 1' 中的'1')都将在 SQL 中转换为常量。我建议使用变量,因为这会在 SQL 查询中引入参数,从而增加查询计划可以在服务器上重用的机会。

另一种可能有用的方法是利用对查询中表达式变量的引用的支持,例如,您可以将 Expression> 类型的变量传递给 Where 子句,稍后将变量的值替换为正确的谓词. 如果我没记错的话,LINQ to Entities 通过将 AsQueryable 运算符应用于查询中的集合,支持使用表达式变量作为​​嵌套集合的谓词条件。否则,您可以利用 LINQ 工具包提供的对 AsExpandable 的支持。您将在 LINQ Kit 主页中找到有关此的更多信息以及使用对表达式变量的引用的示例:http ://www.albahari.com/nutshell/linqkit.aspx 。

我会考虑的第四个也是最复杂的方法是在执行查询之前使用我自己的访问者(例如,从 System.Linq.Expressions.ExpressionVisitor 派生)重写 LINQ 表达式树(在这种情况下从谓词中删除条件) . 我没有一个非常方便的表达式访问者。相反,我可以提供一些解决问题不同部分的文章的指针:

  1. StackOverflow 中的这个线程描述了如何使用表达式访问者进行一些查询重写:使用 LINQ ExpressionVisitor 将原始参数替换为 lambda 表达式中的属性引用
  2. Alex James 的这篇很棒的博客文章描述了如何编写一个拦截查询提供程序,它将在执行查询之前调用您的表达式重写访问者:http: //blogs.msdn.com/b/alexj/archive/2010/03/ 01/tip-55-how-to-extend-an-iqueryable-by-wrapping-it.aspx
  3. 以下文章描述了一个可用于根据规则重写表达式的库:http: //www.codeproject.com/Articles/24454/Modifying-LINQ-Expressions-with-Rewrite-Rules

希望这可以帮助!

于 2013-01-09T22:16:31.407 回答