4

我试图弄清楚如何解决这个问题:

我有 3 个具有多对多关系的表。

Users *-* Roles *-* Permissions

我使用 ORM 从他们那里获取数据。

我的业务层的一个方法必须返回每个权限的用户,所以我用这个类返回对象:

public class UsersPerPermission
{
    public User[] {get;set;}
    public Permission {get;set;}
}

但是这个类没有映射到存储库中的任何表,它是我从现有表中生成的。这个班级应该住在哪里?

换句话说:

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

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

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

谢谢!

PS:这个中间对象叫什么名字?“转变”?

4

3 回答 3

4

在 DDD 中,大多数实体和值对象应该对应于作为通用语言一部分的已识别领域概念。我通常会尽量限制多对多关系和人为关联对象。Eric Evans 在他的书中描述了一些允许这样做的技术。当我必须创建一个关联对象时,它必须有一个关于域的有意义的名称,基本上我从不命名它Class1ToClass2。在您的场景中,由于您的 object ,它更加人为:

  • 对原始模型中已经存在(间接)的关联进行冗余建模。
  • 有一个不反映任何特定业务概念的名称。

请注意,如果我们在表示层或应用程序层中,这种对象不会毫无用处,因为它可以派上用场,以便拥有一个包含屏幕上显示内容的结构 (DTO)。但是我这里说的是领域层,应该没有这样的复合对象。

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

于 2012-09-02T08:28:29.540 回答
0

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

有两种方法可以使用现有的域类“用户”、“角色”和“权限”来实现您的用例。


解决方案一:

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

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

我会GetPermittedUsers() : List<User>在 Permission 类中添加一个方法,这很容易实现。

UI 逻辑将调用 PermissionRepository 的 GetPermissions(),然后在每个 Permission 上调用 GetPermittedUsers()。

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


解决方案二:

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

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

我将添加getUsersByPermissions(List<long> permissionIds) : List<Users>到 UserRepository,并添加getPermissions() : List<Permission>到 User 类。

UserRepository 的实现需要在一个查询中将 User、Role 和 Permission 表连接在一起,并一次性加载所有内容。同样,大多数 ORM 都会正确处理它。

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


老实说,我很喜欢解决方案之一。我避免编写一个复杂的方法来将用户列表转换为权限和用户的映射,因此我不需要担心将这个方法放在哪里。但是,如果您已经具有另一个方向的导航能力,则解决方案可能会在 User、Role 和 Permission 类之间创建循环关系。有些人不喜欢循环关系。如果您的用户案例需要,我认为循环关系有时是可以接受的,甚至是必要的。

于 2012-09-08T22:13:52.020 回答
0

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

IEnumerable<KeyValuePair<PermissionName, IEnumerable<Username>>>

通过使用 KeyValuePair<>,我避免了用人为概念(如 UsersPerPermition)污染域模型。此外,这样的结构是不可变的。我没有在存储库上使用查询方法,因为在我的上下文中,没有实体与另一个实体耦合。因此,任何存储库都无关紧要。

但是,此解决方案对您的 GUI 有用,当且仅当您正确地建模了实体的标识符(在您的示例中,权限和用户都是实体)。实际上,如果它们是属于您的用户理解的通用语言的共享标识符,那么它们就足够了,无需进一步描述。

否则,您只是在为您的 GUI 构建一个有用的 DTO。它不属于域,因此您应该使用最简单的可行方法(ADO.NET 查询?更简单的东西?)。实际上,在我自己的场景中,GUI 和域都使用了这样的服务(GUI 显示了详细说明的预览)。

一般来说,领域模型必须反映领域专家的语言,捕获与有界上下文相关的知识。其他一切都必须在域之外(但大部分时间可以用域的值对象来表示)。

于 2012-09-09T11:03:18.600 回答