存储库模式、POCO、ORM和中间实体

存储库模式、POCO、ORM和中间实体,orm,domain-driven-design,repository-pattern,ddd-repositories,Orm,Domain Driven Design,Repository Pattern,Ddd Repositories,我正试图找出如何解决这个问题: 我有3张具有多对多关系的表 Users *-* Roles *-* Permissions 我使用ORM从他们那里获取数据 我的业务层的方法必须按权限返回用户,因此我返回具有此类的对象: public class UsersPerPermission { public User[] {get;set;} public Permission {get;set;} } 但是这个类没有映射到存储库中的任何表,它是我从现有表生成的。这个班应该住在哪里

我正试图找出如何解决这个问题:

我有3张具有多对多关系的表

Users *-* Roles *-* Permissions
我使用ORM从他们那里获取数据

我的业务层的方法必须按权限返回用户,因此我返回具有此类的对象:

public class UsersPerPermission
{
    public User[] {get;set;}
    public Permission {get;set;}
}
但是这个类没有映射到存储库中的任何表,它是我从现有表生成的。这个班应该住在哪里

换言之:

  • 我是否应该有一个
    IRepository.GetUsersPerPermission()
    ?然后该类应该存在于存储库中

  • 或者我应该有一个
    IBusinessLayer.GetUsersPerPermission()
    ?然后我必须调用存储库中的CRUD方法

只将其放在业务层是有意义的,因为存储库应该只向表公开CRUD操作。。。但是,为了从业务层执行此操作,我必须执行几个独立的查询来获取数据并创建“UserPerPerPerPermission”类。另一方面,如果我将其放在存储库中,我可以使用分组一次性获得该信息

谢谢


PS:这个中间对象的名称是什么?”转换“?

在DDD中,大多数实体和值对象都应该对应于已识别的领域概念,这些概念是您的应用程序的一部分。我通常尽量限制多对多关系和人工关联对象。埃里克·埃文斯在他的书中描述了一些技术。当我必须创建一个关联对象时,它必须有一个关于域的有意义的名称,基本上我从不将其命名为
classatclass2
。 在您的场景中,由于您的对象:

  • 对原始模型中已经(间接)存在的关联进行冗余建模
  • 其名称不反映任何特定的业务概念
请注意,如果我们在表示层或应用程序层,这种对象并不是无用的,因为它可以方便地拥有一个包含屏幕上显示的内容(DTO)的结构。但我在这里谈论的是域层,它应该没有这样的复合对象


因此,我不会首先创建一个
UsersPerPermission
类。如果您想要的是用户列表,而用户是聚合根,那么只需在
UserRepository
中创建一个
GetUsersByPermission()
方法。这并不意味着应用程序服务中也不能有
GetUsersByPermission()
方法,只要它与应用程序的用例相匹配(显示一个权限的详细信息和具有该权限的用户列表的屏幕)。

我同意guillaume31的观点,即不需要引入域对象“UsersPerPermission”支持单个用例

有两种方法可以使用现有的域类“User”、“Role”和“Permission”实现用例


解决方案一:

假设您有:权限-->角色-->用户

箭头表示可导航性。权限与角色列表关联,角色与用户列表关联

我将向Permission类中添加一个方法
getPermistedUsers():List
,该方法实现起来很简单

UI逻辑将调用PermissionRepository的GetPermissions(),然后对每个权限调用GetPermissionDusers()

我假设您使用一个ORM框架,比如hibernate(Nhibernate)并正确定义多对多关系。如果您为角色和用户定义了“从权限中快速加载”,ORM将生成一个查询,将权限表、角色表和用户表连接在一起,并一次性加载所有内容。如果您为角色和用户定义了“延迟加载”,则在调用Permis时,您将在一个查询中加载权限列表然后在另一个查询中加载所有关联的角色和用户。所有内容都是从数据库加载的,最多有三个查询。这称为1+n问题,大多数ORM都能正确处理


解决方案二:

假设您拥有:用户-->角色-->权限

箭头表示可导航性。用户具有角色列表。角色具有权限列表

我会将
getUsersByPermissions(List permissionid):List
添加到UserRepository,并将
getPermissions():List
添加到User类

UserRepository的实现需要在一个查询中将用户表、角色表和权限表连接在一起,并一次性加载所有内容

一旦你有了一个用户列表,你就可以很容易地创建一个方法来构建一个
Map



老实说,我非常喜欢解决方案一。我避免编写一个复杂的方法来将用户列表转换为权限和用户的映射,因此我不需要担心将此方法放在何处。但是,解决方案一可能会在用户、角色和权限类之间创建循环关系,如果您在另一个目录中已经具有导航能力部分。有些人不喜欢循环关系。我认为循环关系是可以接受的,即使有时你的用户案例需要它也是必要的。

在类似的上下文中,我在域服务中使用了一个查询方法,返回类似

IEnumerable<KeyValuePair<PermissionName, IEnumerable<Username>>>
IEnumerable
通过使用KeyValuePair,我避免了人为概念(比如usersperperPermition)污染域模型,而且这种结构是不可变的。 我没有对存储库使用查询方法,因为在我的上下文中,没有实体与其他实体耦合,所以这对任何存储库都没有关系

但是,如果并且仅当您正确地建模了实体的标识符时(在您的示例中,权限和用户都是实体),此解决方案对您的GUI非常有用。 事实上,如果它们是属于你的用户所使用的无处不在的语言的话