尝试遵循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
第一个解决方案也允许最终用户修改角色(重命名,添加新角色等)而不破坏域模型,而在第二个解决方案中,我不确定如何干净地更新它们(通过更新它们)用户,通过文章?)
答案 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可以为您执行此操作时,为什么会混淆业务层?