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() 的目的是啥?的主要内容,如果未能解决你的问题,请参考以下文章
linq中AsEnumerable和AsQueryable的区别
为啥类 DBSet 的 AsQueryable() 不在 MSDN 文档中?