OData和仓储模式中的IEnumerable与IQueryable有何区别?

5
我观看了这个视频并阅读了这篇博客文章。文章的最后一部分让我感到困惑。在最后一部分中,Mosh强调道:仓储不应该返回IQueryable,因为这会导致性能问题。但我读到了一些听起来矛盾的内容。
以下是令人困惑的部分: IEnumerable:当从数据库查询数据时,IEnumerable在服务器端执行select查询,在客户端内存中加载数据,然后过滤数据。因此需要更多的工作并变得缓慢。 IQueryable:当从数据库查询数据时,IQueryable在服务器端执行带有所有过滤器的select查询。因此需要更少的工作并变得更快。 这是关于仓储模式中IQueryable与IEnumerable的另一个答案
这些与Mosh的建议相反。如果这些是正确的,为什么我们不应该使用IQueryable而不是IEnumerable呢?
还有一件事,当我们想要使用OData时怎么办?正如您所知,使用IQueryable查询OData时比使用IEnumerable更好。
还有一件事,对于查询电子商务网站API是否使用OData是好的还是坏的?
请让我知道您的意见。
谢谢。

我遇到了非常相似的问题,我已经认定这是可以接受的。如果你有一个暴露了IQuerable<T> Find(Expression<Func<T, bool>> predicate)或类似的存储库 - 你可以传入筛选器的初始要求集,然后允许应用程序完成其余部分。如果IQuerable被正确实现,那么实际执行将被推迟直到需要它。 - Travis Sharp
1
我所能想到的唯一争议是,如果您需要选择字段的子集而不是整个对象。您仍然可以做到这一点,但是使用自定义提供程序会变得更加困难。 - Travis Sharp
1个回答

1

一个仓库不应该返回 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和业务逻辑的代码必须始终是集成测试(针对数据库),因为Linq to Sql与Linq to Objects不同。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接