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

时间:2011-11-08 17:11:27

标签: c# asp.net-mvc database domain-driven-design dns

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

如果我们有以下类型(纯粹为此示例创建):

class User
{
    ...
}

class Article
{
    ...
}

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

我的想法是让Repositories对这些对象执行CRUD操作,还让Role拥有它自己的Repository,也许可以通过服务访问?

存储库会将UserDTO和ArticleDTO输出到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
    }
}

这个想法有什么本质上的错误吗? e.g:

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

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

3 个答案:

答案 0 :(得分:1)

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

当你说“允许最终用户修改角色”时,我不确定你的意思。如果角色是一个单独的概念,他们应该有自己的域类来表示可以对角色执行的操作(重命名,删除等)。

此外,您的代码段可能看起来像这样(使用泛型而不是上面代码段中的无效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的共享标识(以便您可以删除Roles表中的itemType列)。或者,你可以只使用GUID作为实体ID,这使得很多事情变得更容易。

答案 1 :(得分:0)

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

我不喜欢你的代码是静态RoleBuilder。第一:它是静态的,导致耦合。第二:RoleBuilder不应该从存储库中检索任何内容,而是通过某些服务获取某些实例推送,例如构建角色模型或仅从该数据中获取列表。如果你让RoleBuilder查询Repo,你将Builder的责任与查询逻辑结合起来。

UserBuilder实现可能会出现另一个问题。为了获取可能没问题的单个用户,但是使用该逻辑获取多个用户将导致选择N + 1。

答案 2 :(得分:0)

您对多关系表的第二个想法更合适。使用第一种方法,您将无法在数据库中维护干净的外键。您应该能够从任一实体更新角色,它将反映在另一个实体的存储库中的下一个获取中。在我看来,通常最好将引用完整性保留在数据库中,并且两个连接表都具有到角色表的外键,它将阻止您在附加到文章时从用户实体中删除角色等操作实体。虽然第一个解决方案很聪明,但您必须实现一些业务逻辑以确保数据完整性...当ORM可以为您执行此操作时,为什么会混淆业务层?