从ef表达式树中删除一个条件 [英] remove a condition from ef expression tree

查看:92
本文介绍了从ef表达式树中删除一个条件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用实体框架来处理MVC应用程序中的数据库:我为应用程序创建了一个搜索引擎,使用起始窗体中的几个字段,并设置了来自用户角色的权限,因此创建选择的例程声明越来越多,所以有时我有这种情况。
在我进行选择之前:


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



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


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



    这只是一个简单的例子,因为这样做,我松动了我在Linq表达式树中完成的其他过滤器,并且因为我经常要求添加功能,这是非常困难的要重新组织所有的代码,以测试所有的前提条件,才能在表达式树中添加条件,所以我想知道是否可以删除linq表达式树中的一个语句,并且在树被解析和转换之前sql查询


luca

解决方案

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



如果您不可能推迟查询的创建(在我看来,这是您正在说的话),但您仍然可以预测哪些条件可能需要稍后删除,我会考虑在查询中引入一个布尔哨兵,例如基于您的查询代码段:

  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的这篇伟大的博客文章描述了如何编写一个拦截查询提供程序,该提供程序将在执行查询之前调用您的表达式重写访问者:
    / / /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

希望这有帮助!


I'm using entity framework to handle the database in a MVC application: I created a search engine for the application using several fields from start form, and setting privileges that comes from the user role, so the routine that create the select statement is growing, so sometimes I have this situation. before i make a selection:

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

    after in the source code, in some cases, type of users, filter combinations, and so on, I have to change this filter or remove this condition

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

    this is just a simple example, because doing this way i loose the other filters I have done in the Linq expression tree, and cause i have request to add features very often, it's very difficult to reorganize all the code to test all the prerequisite before to add conditions to the expression tree so i would like to know if is possible to remove a statement in the linq expression tree after has been added and before the tree is parsed and converted in a sql query

luca

解决方案

Assuming I understand your question correctly, I believe the simplest possible approach is to defer the creation of the query until you have collected all the data needed to know what the query should look like, i.e. in this case it would mean you build the query only after you already know whether the condition actually needs to be applied.

If it is not possible for you to defer the creation of the query (it seems to me that is what you are saying), but you can still anticipate which conditions may need to be removed at a later point, I would consider introducing a Boolean sentinel in the query, e.g. based on your query snippet:

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

The variables 'isFirstConditionRelevant' and 'isSecondConditionRelevant' would be initially be set to true and would be captured by the query expression, but you could set to false at a later point (e.g. just before executing the query) if you needed the corresponding condition to have no effect. Notice that with this approach the SQL translation of the query will still contain the condition, but it will also contain a parameter for each sentinel that will short circuit the Boolean logic when the query is executed by the server.

Note also that any constants in your conditions (e.g. the '1' in 'ord.Channel == 1') will be translated to constant in the SQL. I would suggest using variables as this will introduce parameters in the SQL query that could increase the chances that the query plan can be reused on the server.

Another approach that could be useful is to take advantage of support for references to expression variables in the query, e.g. you could pass a variable of type Expression> to the Where clause and at a later point replace the value of the variable to the right predicate. If I remember correctly, LINQ to Entities supports using expression variables as predicate conditions over nested collections by applying the AsQueryable operator to the collection in the query. Otherwise you can take advantage of the support for AsExpandable in provided by the LINQ kit. You will find more information about this, as well as examples of using references to expression variables in the LINQ Kit home page: http://www.albahari.com/nutshell/linqkit.aspx.

The fourth and most complicated approach I would consider is to use my own visitor (e.g. derived from System.Linq.Expressions.ExpressionVisitor) to rewrite the LINQ expression tree (in this case to remove the condition from the predicate) before the query is executed. I don't have an expression visitor that does exactly that handy. Instead, I can provide a few pointers to articles that solve different parts of the problem:

  1. This thread in StackOverflow describes how to use an expression visitor to do some query rewriting: Using a LINQ ExpressionVisitor to replace primitive parameters with property references in a lambda expression.
  2. This great blog post by Alex James describes how to write an intercepting query provider that will call your expression rewriting visitor just be fore the query is executed: http://blogs.msdn.com/b/alexj/archive/2010/03/01/tip-55-how-to-extend-an-iqueryable-by-wrapping-it.aspx.
  3. The following article describes a library that can be used to rewrite expressions based on rules: http://www.codeproject.com/Articles/24454/Modifying-LINQ-Expressions-with-Rewrite-Rules.

Hope this helps!

这篇关于从ef表达式树中删除一个条件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆