多个实体共享相同的角色关系表

本文关键字:角色 关系 实体 共享 | 更新日期: 2023-09-27 18:13:45

尝试遵循DRY原则,下面是让多个对象共享公共角色关系表的有效方法吗?

如果我们有以下类型(纯粹为这个例子创建):

class User
{
    ...
}
class Article
{
    ...
}

这两个对象都需要针对它们定义角色。因此,Role对这些对象中的任何一个都不是唯一的。

我的想法是让存储库对这些对象执行CRUD操作,但也让角色拥有自己的存储库,可能通过服务访问?

存储库将UserDTO和articleledto提供给Builder类,该类将生成必要的Domain对象。在本例中:

class User
{
    ...
    IList<Role> Roles { get; set; }
    //Other Domain objs/logic
}
class Article
{
    ...
    IList<Role> Roles { get; set; }
    //Other Domain objs/logic
}

角色对象将有一个角色表:

ID名称

和关系表:

itemId roleId itemType

用于将角色附加到域对象的角色构建器/服务可能看起来像这样:

static class RoleBuilder
{
    IEnumerable<Role> Fetch(int id, typeof(obj))
    {
        //fetch from RoleRep
    }
    bool Save(IEnumerable<Role>, int id, typeof(obj))
    {
        //save through role rep
    }
}

这个想法有什么内在的错误吗?例句:

public static UserBuilder
{
    public User FetchUser(int id)
    {
        //map userDTO to user
        var user = map...
        //populate roles
        if(user != null)
            user.Roles = RoleBuilder.Fetch(id, typeof(user));
    }
}

另一种选择是让User和Article管理他们自己的角色操作,也许有多个角色关系表,例如user_has_roles, article_has_roles

第一个解决方案将允许最终用户也修改角色(重命名,添加新角色等),而不会损坏域模型,而在第二个解决方案中,我不确定如何干净地做到这一点(通过用户,通过文章更新它们?)

多个实体共享相同的角色关系表

如果角色的概念与用户和文章是分开的-这听起来像是,因为它适用于这两个领域对象-那么我可能会像你建议的那样单独建模。

我不确定你说的"允许角色也被最终用户修改"是什么意思。如果角色是一个独立的概念,它们可能应该有自己的域类来表示可以对角色执行的操作(重命名、删除等)。

同样,你的代码片段应该看起来像这样(使用泛型而不是上面代码片段中无效的typeof()语法):

static class RoleBuilder {
    static IEnumerable<Role> Fetch<T>(int id) {
        switch(typeof(T)) { ... }
    }
    static bool Save<T>(IEnumerable<Role> roles, int id) {
        switch(typeof(T)) { ... }
    }
}

我可能还会考虑为所有可以分配角色的域对象提供某种基类(如果角色用于安全,那么可能是SecurableEntity或其他东西),然后你可以在DB中有一个基类表来支持ID的共享身份(这样你就可以摆脱角色表中的itemType列)。或者,您可以只使用GUID作为实体ID,这会使很多事情变得容易得多。

你的主意听起来不错。我将避免将角色(或者更一般的一些授权系统)与文章和用户模型结合在一起。

我不喜欢你的代码是静态的RoleBuilder。首先,它是静态的,这会导致耦合。第二:RoleBuilder不应该从存储库中检索任何东西,而是获取一些实例,例如由某些服务推入,并从这些数据构建角色模型或只是一个列表。如果您让RoleBuilder查询Repo,则将Builder的职责与查询逻辑耦合在一起。

另一个问题可能来自您的UserBuilder实现。对于抓取单个用户,这可能是可以的,但用该逻辑抓取多个用户将导致Select N+1。

关于多个关系表的第二个想法更合适。使用第一种方法将无法在数据库中维护干净的外键。您应该能够从任何一个实体更新角色,并且它将反映在另一个实体的存储库的下一个获取中。在我看来,通常最好将参考完整性保留在数据库中,并且两个连接表都有role表的外键,这将防止您在用户实体附加到Article实体时从用户实体中删除角色。尽管第一个解决方案很聪明,但您必须实现一些业务逻辑来确保数据完整性……当ORM可以为您做这些事情时,为什么要用这种东西来扰乱您的业务层呢?