AsQueryable() 的目的是啥?
Posted
技术标签:
【中文标题】AsQueryable() 的目的是啥?【英文标题】: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
的真正用例是什么?
【问题讨论】:
【参考方案1】:有几个主要用途。
正如其他答案中提到的,您可以使用它来模拟使用内存数据源的可查询数据源,以便您可以更轻松地测试最终将在基于不可枚举的 @987654321 上使用的方法@。
您可以编写辅助方法来操作可应用于内存序列或外部数据源的集合。如果您编写帮助方法以完全使用IQueryable
,您可以在所有可枚举项上使用AsQueryable
来使用它们。这使您可以避免编写非常通用的辅助方法的两个单独版本。
它允许您将可查询的编译时类型更改为IQueryable
,而不是更多派生类型。有效;您将在 IQueryable
上使用它,同时在 IEnumerable
上使用 AsEnumerable
。您可能有一个实现 IQueryable
的对象,但它也有一个实例 Select
方法。如果是这种情况,并且您想使用 LINQ Select
方法,则需要将对象的编译时类型更改为 IQueryable
。您可以直接转换它,但是通过使用 AsQueryable
方法,您可以利用类型推断。如果泛型参数列表很复杂,这会更方便,如果任何泛型参数是匿名类型,这实际上是必要的。
【讨论】:
感谢复兴。将其标记为答案,因为它是最完整的。 鉴于IQueryable<T>
派生自IEnumerable<T>
,您能解释一下“基于不可枚举的 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
是一个用于迭代和处理数据流的接口。
【讨论】:
您介意改写一下吗:“可以枚举不需要的数据结构或具有有效的枚举器”。我了解IQueryable
和IEnumerable
之间的区别,但我不了解AsQueryable
扩展方法的用例。不过,我对这句话有点困惑,我怀疑这可能是我正在寻找的答案(基于赞成票)。
@Ocelot20:这意味着实现 IQueryable 的提供者提供的帽子数据结构可能不提供枚举能力。这取决于提供者。引用文档:“调用 Execute 方法时执行不返回可枚举结果的查询。”
也许我遗漏了一些明显的东西,但我仍然看不到“为什么我需要使用AsQueryable()
?”的答案。如果我开始使用 IEnumerable(已经能够提供枚举功能的东西),为什么我需要使用扩展方法 AsQueryable()
转换为 IQueryable
?也许一个小代码示例来说明这会派上用场?我似乎在你的解释中遗漏了一些东西。感谢您的宝贵时间。
@Ocelot20:要真正展示我需要编写查询提供程序的区别。你知道我们有linq to sql
、linq to xml
等等.. 如果你想编写linq
驱动程序以你的 数据结构(linq to your data
)为目标,那么你的 api 用户将拥有可以针对 your 数据结构运行 linq
查询,您必须选择 IQueryable
您似乎在解释IQueryable
和IEnumerable
之间的区别。我知道区别,这不是我要的。我在问为什么有人要采用实现IEnumerable
的东西,并使用AsQueryable
扩展方法将其转换为IQueryable
。你是这么回答的吗?我还是说不出来..以上是关于AsQueryable() 的目的是啥?的主要内容,如果未能解决你的问题,请参考以下文章