AsQueryable()的用途是什么
本文关键字:是什么 AsQueryable | 更新日期: 2023-09-27 18:20:21
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
的真实用例是什么?
有几个主要用途。
-
如其他答案中所述,您可以使用它来模拟使用内存中数据源的可查询数据源,这样您就可以更容易地测试最终将在基于不可枚举的
IQueryable
上使用的方法。 -
您可以编写用于操作集合的辅助方法,这些方法可以应用于内存序列或外部数据源。如果您编写的帮助方法完全使用
IQueryable
,那么您只需在所有可枚举对象上使用AsQueryable
即可使用它们。这允许您避免编写两个单独版本的非常通用的辅助方法。 -
它允许您将可查询的编译时类型更改为
IQueryable
,而不是更派生的类型。有效;您将在IQueryable
上使用它,同时在IEnumerable
上使用AsEnumerable
。您可能有一个实现IQueryable
的对象,但它也有一个实例Select
方法。如果是这种情况,并且希望使用LINQSelect
方法,则需要将对象的编译时类型更改为IQueryable
。您可以直接强制转换它,但通过使用AsQueryable
方法,您可以利用类型推断。如果泛型参数列表很复杂,这会更方便,而且如果任何泛型参数都是匿名类型,则实际上是必需的。
我对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()方法允许我在设置mock时满足编译器的要求。
不过,我对应用程序代码中使用这一点很感兴趣。
正如sanjuro所指出的,AsQueryable()的目的在将AsQueryable与Linq-To对象和Linq-To SQL一起使用中进行了解释。文章特别指出,
这在实体上的某些方法返回IQueryable of T,而某些方法返回List的真实场景中提供了极好的好处。但是,不管集合是以T的IQueryable还是T的IEnumerable返回,都需要对所有集合应用业务规则过滤器。从性能的角度来看,如果集合实现了IQueryable,那么您真的希望利用在数据库上执行业务过滤器,否则就可以使用Linq在内存中应用业务过滤器来实现委托。
本文使用带有Linq-To对象和Linq-To SQL 的AsQueryable对AsQueryable()的目的进行了详细解释
来自MSDN Queryable.AsQueryable方法的备注部分:
如果源的类型实现了IQueryable,那么AsQueryable(IEnumerable)将直接返回它。否则,它将返回一个IQueryable,通过调用Enumerable中的等效查询运算符方法而不是Queryable中的方法来执行查询。
这正是上述文章中提到和使用的内容。在您的示例中,它取决于orderRepo.GetAll返回的内容、IEnumerable或IQueryable(Linq到Sql)。如果返回IQueryable,Count()方法将在数据库上执行,否则将在内存中执行。仔细看参考文章中的例子。
接口IQueryable
引用文档:
IQueryable接口旨在通过查询实现供应商。
因此,对于那些打算在.NET中使其数据处理可查询的人来说,不必要的数据结构可以被枚举或具有有效的枚举器。
IEnumerator
是一个用于迭代和处理数据流的接口。