我正在使用我自己的 IQueryable<> 扩展方法 创建可链接查询,例如 FindAll().FindInZip(12345).NameStartsWith("XYZ").OrderByHowIWantIt() 等,然后在延迟执行时根据我的扩展方法链创建单个查询。
但问题是,扩展链中的所有位置(FindXYZ、FindInZip 等)将始终组合为 AND,这意味着我不能执行如下操作:
FindAll().FirstNameStartsWith("X").OrLastNameStartsWith( “Z”)因为我不知道如何在单独的Where方法中注入OR。
知道我该如何解决这个问题吗?
额外的;
到目前为止,我了解如何将表达式链接为 Or 如果我包装它们(例如 CompileAsOr(FirstNameStartsWith("A").LastNameStartsWith("Z").OrderBy(..))
我想做的事情稍微复杂一些(PredicateBuilder 在这里没有帮助..)因为我希望稍后的 IQueryable 基本上可以访问之前建立的 Where 条件,而不必包装它们以在它们之间创建 Or
因为每个扩展方法都返回 IQueryable<> 我。理解它应该了解某处查询条件的当前状态,这使我相信应该有某种自动化的方式或在所有先前的Where条件中创建一个Or,而不必包装您想要的Or'd。
I am using my own extension methods of IQueryable<> to create chainable queries such as FindAll().FindInZip(12345).NameStartsWith("XYZ").OrderByHowIWantIt() etc. which then on deferred execution creates a single query based on my extension methods chain.
The problem with this though, is that all Where's in the extension chain (FindXYZ, FindInZip etc.) will always combine as AND which means I can't do something like this:
FindAll().FirstNameStartsWith("X").OrLastNameStartsWith("Z") because I don't know how I can inject the OR in a separate Where method.
Any idea how I can solve this?
additional;
So far I understand how to chain expressions as Or if I wrap them (e.g. CompileAsOr(FirstNameStartsWith("A").LastNameStartsWith("Z").OrderBy(..))
What I'm trying to do though is slightly more complicated (and PredicateBuilder doesn't help here..) in that I want a later IQueryable to basically access the Where conditions that were established prior without having to wrap them to create the Or between them.
As each extension method returns IQueryable<> I understand that it should have the knowledge about the current status of query conditions somewhere, which leads me to believe that there should be some automated way or creating an Or across all prior Where conditions without having to wrap what you want Or'd.
发布评论
评论(4)
我假设查询的不同部分仅在运行时才知道,即您不能只在
where
中使用||
...一个惰性选项是 < code>Concat - 但这往往会导致糟糕的 TSQL 等; 但是,我倾向于编写自定义表达式。 采取的方法取决于提供程序是什么,因为 LINQ-to-SQL 支持 EF 的不同选项(例如)——这在这里具有真正的影响(因为您不能在 EF 中使用子表达式)。 你能告诉我们是哪一个吗?
下面是一些应该与 LINQ-to-SQL 一起使用的代码; 如果您构建一个表达式数组(或列表,并调用
.ToArray()
),它应该可以正常工作; 示例是 LINQ-to-Objects,但应该仍然有效:I'm assuming the different parts of the query are only known at runtime, i.e. you can't just use
||
in awhere
...One lazy option is
Concat
- but this tends to lead to poor TSQL etc; however, I tend to be inclined to write customExpression
s instead. The approach to take depends on what the provider is, as LINQ-to-SQL supports different options to EF (for example) - which has a genuine impact here (since you can't use sub-expressions with EF). Can you tell us which?Here's some code that should work with LINQ-to-SQL; if you build an array (or list, and call
.ToArray()
) of expressions, it should work fine; example is LINQ-to-Objects, but should still work:使用
PredicateBuilder
。 这可能就是你想要的。Use
PredicateBuilder<T>
. It's probably what you want.在理想的世界中,我个人认为
||
和&&
运算符将是最简单和可读的。 但是它不会编译。因此我使用对此的扩展方法。 在你的例子中它看起来像这样:
.Where(FindInZip(12345).Or(NameStartsWith("XYZ")).And(PostedOnOrAfter(DateTime.Now))
。而不是:
.Where(FindInZip(12345) || NameStartsWith("XYZ") && (PostedOnOrAfter(DateTime.Now))
表达式示例:
扩展方法:
一篇关于扩展表达式的 LINQ 查询的非常好的文章。 .
https://www.red-gate.com/simple-talk/dotnet/net-framework/giving-clarity-to-linq-queries-by-extending-expressions/
In an ideal world I personally think
||
and&&
operators would be the most simple and readable. However it won't compile.Therefore I use an extension method for this. In your example it would look like this:
.Where(FindInZip(12345).Or(NameStartsWith("XYZ")).And(PostedOnOrAfter(DateTime.Now))
.Instead of:
.Where(FindInZip(12345) || NameStartsWith("XYZ") && (PostedOnOrAfter(DateTime.Now))
.Expression example:
Extension method:
A really good article about LINQ Queries by Extending Expressions. Also the source of the extension method that I use.
https://www.red-gate.com/simple-talk/dotnet/net-framework/giving-clarity-to-linq-queries-by-extending-expressions/