.net 如何在使用存储库模式时从EF查询返回单个列

.net 如何在使用存储库模式时从EF查询返回单个列,.net,entity-framework,repository-pattern,data-access,.net,Entity Framework,Repository Pattern,Data Access,我的应用程序的数据访问层由实体框架和存储库模式*组成。使用实体框架日志记录,我发现了一些查询,它们会返回实体的所有列(当然,在retrospect中查看ef查询时,情况显然是这样)。许多低效率和性能问题 通过修改查询来解决这个问题很简单,但我不知道如何将结果从存储库传递回应用程序 通过一个IQueryable打破了我对分离的一切信念 如果我想从存储库层传递一个强类型对象(只包含我想要的列),它需要我的存储库层“知道”其他一些包含dto类的项目(通过项目引用),这让我感觉很不舒服。它创建了一个不

我的应用程序的数据访问层由实体框架和存储库模式*组成。使用实体框架日志记录,我发现了一些查询,它们会返回实体的所有列(当然,在retrospect中查看ef查询时,情况显然是这样)。许多低效率和性能问题

通过修改查询来解决这个问题很简单,但我不知道如何将结果从存储库传递回应用程序

  • 通过一个IQueryable打破了我对分离的一切信念
  • 如果我想从存储库层传递一个强类型对象(只包含我想要的列),它需要我的存储库层“知道”其他一些包含dto类的项目(通过项目引用),这让我感觉很不舒服。它创建了一个不应该存在的程序集依赖项
  • 不能返回匿名类型
我的答案可能是在上述其中一个问题上妥协。但我想先问问社区

*我知道在ORM中使用存储库模式是一个非常有争议的话题,但我真的不想讨论这个问题。我继承了这个应用程序,因此这艘船在应用程序架构方面已经成功了。我只需要一个实用的解决方案,我可以在现有架构的基础上实施,无论我必须接受什么样的妥协

通过一个IQueryable打破了我对分离的一切信念

这是正确的答案。存储库不必知道应用程序可能需要的所有可能的查询。将所有查询逻辑放在存储库中实际上打破了存储库和应用程序其他部分之间的职责分离

要传递强类型对象。。。从存储库层,它要求我的存储库层“了解”其他项目

DTO是应用程序组件之间“契约”的一部分。对于所有应用程序组件来说,共享对服务契约的引用是必要且合适的,包括.NET接口定义和从接口方法传递的数据类型

通过一个IQueryable打破了我对分离的一切信念

我相信这是你问题的根源。:)

我看到的反对使用IQueryable的典型论点是,人们认为存储库的使用者不需要了解模式,并且返回IQueryable“泄漏”EF和模式。我已经看到了足够多的尝试来抽象EF和模式,它们总是导致接受表达式/函数的复杂方法(泄漏EF isms,因为调用方仍然必须传递EF可以接受的表达式树)或者是效率极低的仓库,堆满了数百种方法来满足每个消费者的需求

我对该假设的反驳是,存储库的作用仅仅是抽象数据访问的实现,这样我就可以有效地对消费者进行单元测试。通过利用一个返回IQueryable(并且只有IQueryable)的存储库,我可以模拟一个存储库来返回任何适合测试的实体,以覆盖业务逻辑,而这些实体不属于存储库。使用IQueryable的优势在于,最终您会得到非常精简的存储库,而我的存储库通常只有一个Create方法、一个实体的Read方法(适用于该存储库的使用者),以及一个Delete方法(在我使用软删除或历史模式的情况下)。我认为我的存储库可能会提供一个“ById”类型的方法,因为这通常用于更新等。但是这个方法也会返回IQueryable。如果我正在进行更新,消费者在包含可能也会更新的任何相关实体后调用
.Single()
。其他代码可能只是执行
。任何
检查,或者出于某种目的只想从该实体中选择一些值。这种模式是可适应的

通过利用IQueryable,您可以从实体或其层次结构中高效地选择几个字段。它使用简单,易于理解,并导致高效、快速的查询。受信任的内部调用者可以利用Linq方法使用
.Any
.Count
、分页、排序、筛选等。而
只选择他们需要的数据以满足其特定需求。存储库处理核心级别的过滤规则,如授权、软删除是活动检查等。它可能被滥用,并导致对数据库的丑陋、昂贵的点击,但您编写的任何代码也可能如此。复杂的解决方案更难理解,当它们似乎不适合未来的需求时,它们会导致破坏某些东西的黑客或修改。拥有几十个专门构建的方法的存储库会导致相当大的重复,因为当开发人员需要额外的一列或更少的一列时,他们不必费心筛选不断增长的方法。在我看来,更糟糕的是,这些方法将实体作为容器返回,而容器只是部分填充。实体应始终表示真实、完整的数据状态,因为任何接受实体的方法都不必怀疑该实体的实际完整性


当我写的代码会被其他人触动时,我会专注于让代码更容易理解,更容易发现并纠正错误。我相信,好的代码和体系结构应该使错误易于发现和修复,而不是试图让错误难以犯。

您的回答是深思熟虑的,因此我会重新思考我预先学到的或先入为主的观念。在我回复更多内容之前,我将快速重读关于传回IQueryable的利/弊,以及关于您的DTO评论。快的