为什么 .Where 作为 IEnumerable 而不是 IQueryable?

huangapple go评论68阅读模式
英文:

Why is .Where acting as IEnumerable insteading of IQueryable?

问题

我实现了一个名为 WhereIf 的 IQueryable<T> 类型的扩展/助手,正如你从名称中猜到的那样,它仅在满足预条件时应用过滤,并通过代码在 EntityFramework 查询中链接,但它有两个问题,并且不起作用,而在另一个类似的实现中,它却正常工作。那么为什么第一个 .Where 不起作用,而第二个却正常工作呢?

public static class WhereIfHelper
{
    public static IQueryable&lt;T&gt; WhereIf&lt;T&gt;(this IQueryable&lt;T&gt; source, bool condition, Func&lt;T, bool&gt; expression)
        where T: class
    {
        return condition ? source.Where(expression) : source;
    }
}
  1. .Where() 的类型是 IEnumerable<T>,这导致了运行时异常,所以我使用了 .AsQueryable() 来解决它。
  2. 当我调用它时,抛出了:
    The source &#39;IQueryable&#39; doesn&#39;t implement &#39;IAsyncEnumerable&lt;Model&gt;&#39;. Only sources that implement &#39;IAsyncEnumerable&#39; can be used for Entity Framework asynchronous operations.
    我目前不知道如何解决这个问题。

在第二段代码中,我使用了引用类型而不是泛型,并且没有预条件。

public static class RepositoryIssueExtensions
{
    public static IQueryable&lt;Game&gt; FilterGames(this IQueryable&lt;Game&gt; games,
    DateTimeOffset initialDate,
    DateTimeOffset lastDate) =&gt; games.Where(i =&gt; i.CreatedAt &gt;= initialDate &amp;&amp; i.CreatedAt &lt;= lastDate);
}

这次 .Where 被识别为类型 IQueryable<T>。

英文:

I implemented an extension/helper called WhereIf of Type IQueryable<T>, as you may have guessed by the name of it, it applies the filtering only if a pre-condition is met and is chained in EntityFramework query by code, but there were two problems with it and didn't work, and in another similar implementation, it worked fine.
So why is that the first .Where didn't work but the second works just fine?

public static class WhereIfHelper
{
    public static IQueryable&lt;T&gt; WhereIf&lt;T&gt;(this IQueryable&lt;T&gt; source, bool condition, Func&lt;T, bool&gt; expression)
        where T: class
    {
        return condition ? source.Where(expression) : source;
    }
}
  1. .Where() is of type IEnumarable<T> which caused a runtime exception, so I used .AsQueryable() to solve it.
  2. When I called it threw:
    The source &#39;IQueryable&#39; doesn&#39;t implement &#39;IAsyncEnumerable&lt;Model&gt;&#39;. Only sources that implement &#39;IAsyncEnumerable&#39; can be used for Entity Framework asynchronous operations.
    Which I don't know how to solve at this moment.

In the second code, I used a reference type instead of a generic and without a pre-condition.

public static class RepositoryIssueExtensions
{
    public static IQueryable&lt;Game&gt; FilterGames(this IQueryable&lt;Game&gt; games,
    DateTimeOffset initialDate,
    DateTimeOffset lastDate) =&gt; games.Where(i =&gt; i.CreatedAt &gt;= initialDate &amp;&amp; i.CreatedAt &lt;= lastDate);
}

This time .Where is recognized as type IQueryable<T>.

答案1

得分: 4

Enumerable.Where 接受 Func&lt;&gt; 谓词,而 Queryable.Where 需要对称的 Expression&lt;Func&lt;&gt;&gt;,因为 IQueryable&lt;T&gt; 实现了 IEnumerable&lt;T&gt;,在提供的代码中唯一适用的重载是针对 IEnumerable 的。将该方法更改为接受 Expression&lt;Func&lt;T, bool&gt;&gt;(甚至参数名都是正确的):

public static class WhereIfHelper
{
    public static IQueryable&lt;T&gt; WhereIf&lt;T&gt;(this IQueryable&lt;T&gt; source,
        bool condition, 
        Expression&lt;Func&lt;T, bool&gt;&gt; expression)
        where T: class
    {
        return condition ? source.Where(expression) : source;
    }
}

P.S.

查询提供程序使用表达式树分析传递的方法,并将其转换为其他形式(例如 ORM 的 SQL)。了解更多:

  1. IQueryable<T> 与 IEnumerable<T> 之间的区别是什么?
  2. 表达式树
英文:

Enumerable.Where accepts Func&lt;&gt; predicates while Queryable.Where requires symmetrical Expression&lt;Func&lt;&gt;&gt;'s, since IQueryable&lt;T&gt; implements IEnumerable&lt;T&gt; the only suitable overloads in the provided code are for IEnumerable. Change the method to accept Expression&lt;Func&lt;T, bool&gt;&gt; (you even have right parameter name):

public static class WhereIfHelper
{
    public static IQueryable&lt;T&gt; WhereIf&lt;T&gt;(this IQueryable&lt;T&gt; source,
        bool condition, 
        Expression&lt;Func&lt;T, bool&gt;&gt; expression)
        where T: class
    {
        return condition ? source.Where(expression) : source;
    }
}

P.S.

Expression trees are used by queryable providers to analyze passed method and turn them into something else (like SQL in case of ORMs). Read more:

  1. What is the difference between IQueryable<T> and IEnumerable<T>?
  2. Expression trees

huangapple
  • 本文由 发表于 2023年2月27日 07:49:38
  • 转载请务必保留本文链接:https://go.coder-hub.com/75575726.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定