在OData和Repository Pattern中IEnumerable vs IQueryable

时间:2018-02-24 00:55:46

标签: odata ienumerable repository-pattern iqueryable

我观看了this视频并阅读了this博文。这篇文章中有些东西让我困惑;帖子的最后一部分。在最后一部分中,Mosh强调,存储库永远不应该返回IQueryable,因为它会导致性能问题。但我读到的内容听起来很矛盾。

这是令人困惑的部分:

IEnumerable :在从数据库查询数据时,IEnumerable在服务器端执行select查询,在客户端加载内存中的数据,然后过滤数据。因此,做更多的工作,变得缓慢。

IQueryable :在从数据库查询数据时,IQueryable在服务器端使用所有过滤器执行select查询。因此,工作量减少,变得更快。

this is another answer关于存储库模式中的IQueryable vs IEnumerable。

这些与莫什的建议相反。如果这些都是真的,为什么我们不应该使用IQueryable而不是IEnumerable。

还有别的,我们想要使用OData的情况如何;如您所知,在使用OData查询时,最好使用IQueryable而不是IEnumerable。

还有一件事,使用OData查询电子商务网站API是好还是坏。

请让我知道你的意见。

谢谢

2 个答案:

答案 0 :(得分:1)

莫什想说的是:

我们正在使用存储库模式来实现封装 ”。

当我们返回IQueryable时,随着我们的应用程序的增长,可能有人想对我们的查询进行查询!那是使用IQueryable而不是IEnumerable的有害部分(在所有情况下都不错,但是在这种情况下,这是一个非常糟糕的做法)。

看看他的例子:

 var orders = context.Orders
     .Include(o => o.Details)
         .ThenInclude(d => d.Product)
     .Where(o => o.CustomerId == 1234);
  

这里,我们直接使用DbContext而不使用存储库模式。当您的存储库方法   返回IQueryable,其他人将获得该IQueryable并   在其上撰写查询。结果如下:

var orders = repository.GetOrders()
    .Include(o => o.Details)
         .ThenInclude(d => d.Product)
     .Where(o => o.CustomerId == 1234);

唯一的区别是,在第一个查询中,我们使用 context.Orders ,在第二个查询中,我们使用 repository.GetOrders()。这在查询上是一个很大的重复,因此也会带来严重的性能损失,并且您知道没有问题

那是他说的原因:

  

您的存储库应返回域对象。因此, GetOrders()   方法应返回 IEnumerable 。有了这个,第二个例子可以   改写为:

var orders = repository.GetOrders(1234);

在使用OData作为查询系统的情况下,我们位于同一页面上;因为我们的数据将由第三者查询,而对我们的数据检索模式一无所知。

答案 1 :(得分:0)

存储库不应返回 IQueryable。但不是因为性能。这是由于复杂性。存储库旨在降低业务层的复杂性。

购买暴露 IQueryable 会以两种方式增加复杂性:

  • 您将持久性知识泄露给了业务领域。为了编写有效的查询,您必须了解有关底层 Linq to Sql 提供程序的一些信息。
  • 您必须设计业务实体,以便可以查询它们(即不是纯业务实体)。

示例:

var blockedUsers = _repository.GetBlockedUsers();

//vs

var blockUsers = _dbContext.Users.Where(x => x.State == 1);
var user = _repos.GetById(1);
//and an enum is used internally in the user class
user.Block(); 
_repos.Update(user);

// vs 
var user = _dbContext.Users.FirstOrDefault(x => x.Id == 1);
user.State = 1;
_dbContext.SaveChanges();

通过将所有内容都包装在您的存储库之后,您可以以一种易于使用的方式设计您的业务实体(子实体、枚举、日期管理等)。您可以设计存储库,以便可以有效地存储这些实体。没有妥协和更容易维护的代码。

关于 OData:不要使用存储库模式。在这种情况下,它不会增加任何价值。

如果您坚持在您的业务域中使用 IQueryable,请不要使用存储库模式。它只会使事情复杂化,而不会增加任何价值。

最后:

使用正确设计的存储库的业务逻辑更容易测试(单元测试)。 LINQ 和业务逻辑混合的代码必须始终是集成测试(针对 DB),因为 Linq to Sql 不同于 Linq to Objects。