首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >去仓库还是不去仓库

去仓库还是不去仓库
EN

Software Engineering用户
提问于 2014-04-29 11:06:07
回答 2查看 2.2K关注 0票数 11

当我第一次学习领域驱动设计时,我还被介绍给了存储库和工作模式单元,这些模式曾经似乎是那些把SQL查询(比如警告语言)抛到数据库上的酷孩子们的首选。我对这个话题越深入,就越了解到它们似乎不再必要了,因为像EF和NHibernate这样的ORM将工作单元和存储库都实现为一个API,称为会话或上下文。

现在我不知道该怎么办了。存储库或不存储库。我非常理解这样一种观点,即这种泄漏的抽象只会使事情变得过于复杂,而不会增加任何可能简化数据访问的内容,然而,将我的应用程序的每一个可能的方面都耦合到例如实体框架( Entity )上是不对的。通常,我遵循一些简单的指导原则:

  1. 域层是系统的核心,包含实体、服务、存储库.
  2. 基础设施层提供与基础设施有关的域接口的实现,例如文件、数据库、协议。
  3. 应用层拥有一个组合根,它将事物连接起来并编排所有内容。

我的解决方案通常如下所示:

代码语言:javascript
复制
Domain.Module1
Domain.Module2
    IModule2Repo
    IModule2Service
    Module2
Infrastructure.Persistence
    Repositories
        EntityFrameworkRepositoryBase
MyApp
    Boostrapper
        -> inject EntityFrameworkRepositoryBase into IRepository etc.

我通过使用IRepository<'T>来保持域层的清洁,这也是一个域关注点,而不依赖于告诉我如何访问数据的任何其他内容。当我现在要做一个需要数据访问的IModule2Service的具体实现时,我必须注入DbContext,并以此直接将其耦合到基础结构层。(在Visual项目中,由于循环依赖关系,这可能会变得非常棘手!)

此外,还有什么可以替代保存人和他妈的作品呢?CQRS?如何抽象一个纯粹的基础设施框架?

EN

回答 2

Software Engineering用户

发布于 2014-05-01 07:14:52

工程就是妥协。软件开发也是如此。现在,我认为只有其他更简单的选择是直接与ORM合作。但正如您所说的,这可能会将您锁定在特定的持久性框架中。

因此,您必须扪心自问,“您的代码与持久性脱钩的额外复杂性值得吗?”每当我听到人们说他们想要将他们的代码从持久性中分离出来,我就会问:“在你的职业生涯中,你改变了你的持久性框架多少次了?”

我在存储库中看到的问题是,它们会使常见的更改变得更加困难。例如:添加查询聚合的新方法。它们会使不寻常的改变(据说)变得更容易。例如:更改存储库的实现。

还有一个单元测试参数,我说:“如果持久性框架不允许您在内存或本地模拟数据库,那么就根本不值得使用该框架。”

票数 5
EN

Software Engineering用户

发布于 2017-06-19 13:15:47

我是亲存储库的,虽然我已经远离了一般的存储库模式。相反,我将我的存储库与它们所提供的业务功能对齐。存储库的目的并不是抽象出ORM,因为这并不是我希望改变的东西,同时我也避免使存储库变得过于粒度化。(即CRUD)相反,我的存储库有两个到三个关键目的:

  • 数据检索
  • 数据创建
  • 硬删除

对于数据检索,存储库总是返回IQueryable<TEntity>。对于数据创建,它返回TEntity。存储库处理我的基础级筛选,例如使用软删除模式的系统的授权“活动”状态,以及使用历史数据的系统的“当前”状态。数据创建只负责确保所需的引用被解析和关联,并且实体已经设置并准备就绪。

数据更新是业务逻辑与相关实体(S)一起工作的责任。这可以包括诸如验证规则之类的内容。我不尝试将其封装在存储库方法中。

在我的大多数系统中删除是软删除,因此它将属于数据更新。(IsActive = false)在硬删除的情况下,这将是存储库中的一个一行。

为什么是存储库?测试能力。当然,可以对DbContext进行模拟,但是模拟返回IQueryable<TEntity>的类更简单。它们也很适合使用UoW模式,我个人使用Mehdime的DbContextScope模式在我想要的级别(即控制器在MVC中),并让我的控制器和助手服务类使用存储库,而不需要传递对UoW/dbContext的引用。使用IQueryable意味着存储库中不需要太多的包装方法,并且代码可以优化数据的使用方式。例如,存储库不需要公开诸如“存在”或“计数”之类的方法,也不需要在需要数据子集的情况下使用其他POCOs包装实体。他们甚至不需要为您可能需要或不需要的相关数据处理急切的加载选项。通过传递IQueryable,调用代码可以:

代码语言:javascript
复制
.Any()
.Count()
.Include() // Generally avoided, instead I use .Select()
.Where()
.Select(x => new ViewModel or Anon. Type)
.Skip().Take()
.FirstOrDefault() / .SingleOrDefault() / .ToList()

非常灵活,通过测试P.o.V.,我模拟的存储库只需返回填充实体对象的列表。

至于一般的存储库,我在很大程度上已经不再使用这些存储库了,因为当您以每个表的存储库结束时,您的控制器/服务最终会引用多个存储库来执行一个业务操作。在大多数情况下,实际上只有一两个这样的存储库在执行写操作(前提是您正确地使用导航属性),而其余的存储库则支持那些具有读取功能的存储库。我宁愿拥有类似OrdersRepository的东西,它能够读取和创建订单,以及读取任何相关的查找等(轻量级客户对象、产品等)。用于创建订单时的参考,而不是访问5或6个不同的存储库。它可能违反了DNRY纯粹主义者,但我的论点是,存储库的目的是为创建包含相关引用的订单服务。我不需要使用Repository<Product>来获取产品,在那里,对于订单,我只需要一个包含少数字段的实体。我的OrderRepository可能有一个返回IQueryable<ProductSummary>.GetProducts()方法,我发现这个方法比一个Repository<Product>更好,它最终有几个"Get“方法来尝试并服务于应用程序需要的不同区域,以及/或一些复杂的传递过滤表达式。

我选择更简单的代码,便于跟踪、测试和调优。它可能以不好的方式被滥用,但我更希望有一些滥用很容易发现和纠正的东西,而不是试图以一种不能被滥用、失败的方式“锁定”代码,然后做一些噩梦来实现客户最终付出的代价。:)

票数 3
EN
页面原文内容由Software Engineering提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://softwareengineering.stackexchange.com/questions/237374

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档