【问题标题】:What is the purpose of AsQueryable()?AsQueryable() 的目的是什么?
【发布时间】:2021-11-05 12:15:45
【问题描述】:

AsQueryable() 的目的是为了让您可以将IEnumerable 传递给可能需要IQueryable 的方法,还是有一个有用的理由将IEnumerable 表示为IQueryable?例如,是否应该用于这样的情况:

IEnumerable<Order> orders = orderRepo.GetAll();

// I don't want to create another method that works on IEnumerable,
// so I convert it here.
CountOrders(orders.AsQueryable());

public static int CountOrders(IQueryable<Order> ordersQuery)
{
    return ordersQuery.Count();
}

或者它真的让它做一些不同的事情:

IEnumerable<Order> orders = orderRepo.GetAll();
IQueryable<Order> ordersQuery = orders.AsQueryable();

IEnumerable<Order> filteredOrders = orders.Where(o => o.CustomerId == 3);
IQueryable<Order> filteredOrdersQuery = ordersQuery.Where(o => o.CustomerId == 3);

// Are these executed in a different way?
int result1 = filteredOrders.Count();
int result2 = filteredOrdersQuery.Count();

这些扩展方法的IQueryable 版本是否只是构建了一个表达式,一旦执行,它最终会做同样的事情?我的主要问题是,使用AsQueryable 的真正用例是什么?

【问题讨论】:

    标签: c# .net linq ienumerable iqueryable


    【解决方案1】:

    有几个主要用途。

    1. 正如其他答案中提到的,您可以使用它来模拟使用内存数据源的可查询数据源,以便您可以更轻松地测试最终将在基于不可枚举的 @987654321 上使用的方法@。

    2. 您可以编写辅助方法来操作可应用于内存序列或外部数据源的集合。如果您编写帮助方法以完全使用IQueryable,您可以在所有可枚举项上使用AsQueryable 来使用它们。这使您可以避免编写非常通用的辅助方法的两个单独版本。

    3. 它允许您将可查询的编译时类型更改为IQueryable,而不是更多派生类型。有效;您将在 IQueryable 上使用它,同时在 IEnumerable 上使用 AsEnumerable。您可能有一个实现 IQueryable 的对象,但它也有一个实例 Select 方法。如果是这种情况,并且您想使用 LINQ Select 方法,则需要将对象的编译时类型更改为 IQueryable。您可以直接转换它,但是通过使用 AsQueryable 方法,您可以利用类型推断。如果泛型参数列表很复杂,这会更方便,如果任何泛型参数是匿名类型,这实际上是必要的

    【讨论】:

    • 感谢复兴。将其标记为答案,因为它是最完整的。
    • 鉴于IQueryable&lt;T&gt; 派生自IEnumerable&lt;T&gt;,您能解释一下“基于不可枚举的 IQueryable”是什么意思吗?
    • @Dai 它指的是IQueryable,它不仅仅是一个包装好的IEnumerable,它实际上利用了IQueryable 的附加功能。
    • #1 正是我想要的。感谢您的验证。
    【解决方案2】:

    我对 AsQueryable 最有效的案例是单元测试。假设我有以下有点做作的例子

    public interface IWidgetRepository
    {
       IQueryable<Widget> Retrieve();
    } 
    
    public class WidgetController
    {
       public IWidgetRepository WidgetRepository {get; set;}
    
    
       public IQueryable<Widget> Get()
       {
          return WidgetRepository.Retrieve();
       }
    }
    

    我想编写一个单元测试来确保控制器传回从存储库返回的结果。它看起来像这样:

    [TestMethod]
    public void VerifyRepositoryOutputIsReturned()
    {    
        var widget1 = new Widget();
        var widget2 = new Widget();
        var listOfWidgets = new List<Widget>() {widget1, widget2};
        var widgetRepository = new Mock<IWidgetRepository>();
        widgetRepository.Setup(r => r.Retrieve())
          .Returns(listOfWidgets.AsQueryable());
        var controller = new WidgetController();
        controller.WidgetRepository = widgetRepository.Object;
    
        var results = controller.Get();
    
        Assert.AreEqual(2, results.Count());
        Assert.IsTrue(results.Contains(widget1));
        Assert.IsTrue(results.Contains(widget2));
    }
    

    实际上,所有 AsQueryable() 方法允许我做的就是在设置模拟时满足编译器的要求。

    不过,我会对它在应用程序代码中的使用位置感兴趣。

    【讨论】:

      【解决方案3】:

      正如 sanjuro 所说,Using AsQueryable With Linq To Objects And Linq To SQL 中解释了 AsQueryable() 的用途。文章特别指出,

      这在实际场景中提供了极好的好处,其中您在实体上有某些方法返回 T 的 IQueryable,而某些方法返回 List。但是,您有需要应用于所有集合的业务规则过滤器,无论该集合是作为 T 的 IQueryable 还是 T 的 IEnumerable 返回的。从性能的角度来看,您真的希望利用在数据库上执行业务过滤器,如果集合实现 IQueryable 否则回退到使用 Linq 将内存中的业务过滤器应用于委托的对象实现。

      【讨论】:

        【解决方案4】:

        本文Using AsQueryable With Linq To Objects And Linq To SQL详细解释了AsQueryable()的用途

        来自 MSDN Queryable.AsQueryable 方法的备注部分:

        如果source的类型实现了IQueryable,AsQueryable(IEnumerable)直接返回。否则,它返回一个 IQueryable,它通过调用 Enumerable 中的等效查询运算符方法而不是 Queryable 中的方法来执行查询。

        这正是上面文章中提到和使用的内容。 在您的示例中,这取决于 orderRepo.GetAll 返回的内容、IEnumerable 或 IQueryable(Linq to Sql)。如果它返回 IQueryable,Count() 方法将在数据库上执行,否则它将在内存中执行。仔细查看参考文章中的示例。

        【讨论】:

          【解决方案5】:

          接口IQueryable引用文档:

          IQueryable 接口旨在通过查询实现 供应商。

          因此,对于打算在 .NET 中使其数据结构可查询的人,可以枚举不需要的数据结构或具有有效的枚举器

          IEnumerator 是一个用于迭代和处理数据流的接口。

          【讨论】:

          • 您介意改写一下吗:“可以枚举不需要的数据结构或具有有效的枚举器”。我了解IQueryableIEnumerable 之间的区别,但我不了解AsQueryable 扩展方法的用例。不过,我对这句话有点困惑,我怀疑这可能是我正在寻找的答案(基于赞成票)。
          • @Ocelot20:这意味着实现 IQueryable 的提供者提供的帽子数据结构可能不提供枚举能力。这取决于提供者。引用文档:“调用 Execute 方法时执行不返回可枚举结果的查询。”
          • 也许我遗漏了一些明显的东西,但我仍然看不到“为什么我需要使用AsQueryable()?”的答案。如果我开始使用 IEnumerable(已经能够提供枚举功能的东西),为什么我需要使用扩展方法 AsQueryable() 转换为 IQueryable?也许一个小代码示例来说明这会派上用场?我似乎在你的解释中遗漏了一些东西。感谢您的宝贵时间。
          • @Ocelot20:要真正展示我需要编写查询提供程序的区别。你知道我们有linq to sqllinq to xml 等等.. 如果你想编写linq 驱动程序以你的 数据结构(linq to your data)为目标,那么你的 api 用户将拥有可以针对 your 数据结构运行 linq 查询,您必须选择 IQueryable
          • 您似乎在解释IQueryableIEnumerable 之间的区别。我知道区别,这不是我要的。我在问为什么有人要采用实现IEnumerable 的东西,并使用AsQueryable 扩展方法将其转换为IQueryable。你是这么回答的吗?我还是说不出来..
          猜你喜欢
          • 2023-04-02
          • 1970-01-01
          • 2014-06-02
          • 2011-03-05
          • 2015-03-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多