我观看了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是好还是坏。
请让我知道你的意见。
谢谢
答案 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
会以两种方式增加复杂性:
示例:
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。