在我的域模型中有数据库上下文是否可以

时间:2014-10-18 18:47:11

标签: asp.net-mvc oop architecture onion-architecture

我正在使用ASP.NET MVC开发基于Web的应用程序。我正在尝试使用丰富的域模型而不是瘦/贫模型。

我已经按照洋葱建筑的方式建立了我的解决方案。不同的项目如下: enter image description here

  • {}。Domain.Core - 包含域对象和接口,如基础架构层中实现的IDbContext
  • {}。数据库 - 是数据库项目
  • {]。基础设施 - 包含日志记录,数据访问等实现。
  • {}。网站 - 查看和控制器

****使用dapper完成数据访问,IDbContext是2个简单命令查询接口的包装器。我已将每个查询隔离为单独的类。

为了便于讨论,我将收集一小部分申请。

我有一个版本化的文档库,其中包含文档以及标签,权限等其他元数据

我的文档对象的简化模型如下所示

enter image description here

我希望在域对象中定义操作,因为每个操作都涉及业务逻辑。 让我把“删除”作为一个操作。需要执行操作

  • 验证用户是否有权删除
  • 检查是否没有会受此删除影响的关联
  • 检查是否有正在进行的工作流程
  • 从事务中的数据库中删除实际项目

如上例所示,我需要数据库上下文来完成此操作。 我目前正在考虑建模的方法是让域对象具有IDbContext,它可以执行公开的查询。

enter image description here

在我的控制器类中,我调用域对象并执行操作。

我不确定在域对象中传递IDbContext是否正常?如果没有更好的方法来模拟这个?

我不相信拥有单独的服务层,因为     1)对于大多数情况,控制器充当服务层的第一层     2)服务层只是将相同的方法从域复制到另一个类

让我知道如何改进这种设计。

1 个答案:

答案 0 :(得分:2)

注入IDbContext类似于制定域模型的主要原则,该模型应仅在检索和存储域实体时负责业务逻辑,这是基础架构层的责任。是的,你通过接口注入它,隐藏实际的实现,但它让你的域模型知道一些存储。

此外,删除Document所需的步骤也不一定属于Document对象。让我们考虑使用用户权限的第一步和以下情况:

  • 应允许具有管理员角色的用户删除任何文档
  • 应允许文档所有者删除文档

对于第一种情况,用户和要删除的文档之间可能没有连接。管理员用户只允许做任何事情。这就像一个典型的例子,有两个银行账户和一个转账的操作,涉及两个账户,但不是他们的责任。这是域服务到位的时候。请不要将它们与服务层服务混淆。域服务是域模型的一部分,仅负责业务逻辑。

所以如果我是你,我会用DeleteDocument方法创建一个新的域服务。这应该从上面的前三个步骤接受UserDocument作为参数。第四步应该由您的存储库完成。

不确定你的意思
  

我没有看到添加存储库的重要价值

但从域名模型的角度来看,你已经拥有了IDbContext。我假设你的意思是为每个实体实现存储库或单独的存储库。从长远来看,控制器中的伪代码应该如下:

var user = bdContext<User>.SelectById(userId);
var document = bdContext<Document>.SelectById(docId);
var docService = new DocumentService();
docService.DeleteDocument(document, user);  //  Throw exception here if deletion is not allowed
bdContext<Document>.Delete(document);

如果您希望在应用程序的许多地方需要此逻辑,则可以将其包装在服务层服务中。

如果您想了解有关域建模的更多信息,我建议您阅读关于DDD的Eric Evans book。这将详细讨论实体,值对象,域服务等的含义。

回答评论: 事实上,域服务是域的一部分,因此实现和接口都是域的一部分。两个或多个对象必须相互交互的事实不足以创建域服务。我们以航班预订系统为例。您的Flight实体具有不同的属性,例如DepartureCityArrivalCityFlight实体还应提及席位列表。 Seat也可以是一个单独的实体 属性为Class(商业,经济等),Type(isle,row,middle)等。因此,预订座位需要与不同的参与者互动,例如Flight和{ {1}}但我们不需要域名服务。如果不被视为Seat的子对象,那么自然Seat属性就毫无意义。您甚至不可能从Flight上下文中查询Seat实体。因此,保留FlightSeat实体的责任,可以将保留逻辑放到Flight类中。请注意,这只是一个示例,尝试解释何时需要创建域服务,真正的系统可以完全另一种方式建模。因此,请尝试按照以下三个基本步骤来决定是否需要域名服务:

  
      
  1. 服务执行的操作是指自然不属于实体或值对象的域概念。
  2.   
  3. 执行的操作是指域中的其他对象。
  4.   
  5. 操作是无状态的。
  6.   

我正在从控制器访问dbcontext,该控制器是应用程序/服务层而不是域/业务层。域模型只处理业务逻辑,它不应该知道任何持久性逻辑,从上面的例子可以看出DocumentService没有dbcontext的引用。