这是一个相当长的(不是过于复杂的)设计问题,请耐心等待。我试图通过POJO和JPA实施人员/角色管理系统。我对ORM相当陌生,这主要是映射问题。JPA/Hibernate的继承映射
我已经得到了这个工作作为POJO和我舒适与呼叫者级别的API,但现在想使用JPA将其映射到数据库或在Seam环境中休眠。
我的实现基于Decorator(GoF)和Person Role Object模式(堡盟/ Riehle等人)。所有角色都是硬编码的,并且不支持运行时添加新角色,因为它需要更改代码以扩展行为。我会使用用户组来实现安全性和权限。
有一个Person接口,包含诸如addRole(),removeRole(),hasRole(),getRole(),getRoles()等角色管理方法。具体实现由PersonImpl类提供。
有一个抽象类Role也实现了Person接口(用于装饰器替代等价)以及一个扩展它的RoleImpl类。 Role类持有对个人实例的引用,用它来为人员界面上的任何方法/属性调用提供服务,这意味着Role的所有子类都可以处理Person接口。角色构造函数将person对象作为参数。
这些是接口/类:
public interface Person {
public String getFirstName();
public void setFirstName(String firstName);
.
.
.
public boolean isEnabled();
public void setEnabled(boolean enabled);
public Set<Role> getRoles();
public Role addRole(Class<? extends Role> roleType);
public void removeRole(Class<? extends Role> roleType);
public boolean hasRole(Class<? extends Role> roleType);
public Role getRole(Class<? extends Role> roleType);
public enum Gender {MALE, FEMALE, UNKNOWN};
}
public class PersonImpl implements Person {
.
.
.
}
public abstract class Role implements Person {
protected PersonImpl person;
@Transient
protected abstract String getRoleName();
protected Role() {}
public Role(PersonImpl person) {
this.person = person;
}
public String getFirstName() {
return person.getFirstName();
}
public void setFirstName(String firstName) {
person.setFirstName(firstName);
}
public Set<Role> getRoles() {
return person.getRoles();
}
public Role addRole(Class<? extends Role> roleType) {
return person.addRole(roleType);
}
.
.
.
}
public abstract class RoleImpl extends Role {
private String roleName;
protected RoleImpl() {}
public RoleImpl(PersonImpl person) {
super(person);
}
.
.
.
}
public class Employee extends RoleImpl {
private Date joiningDate;
private Date leavingDate;
private double salary;
public Employee(PersonImpl person) {
super(person);
}
.
.
.
}
下图显示了类之间的关系:
(如果你无法看到图在线,查看这里via yUML)我想用这些类如下:
Person p = new Person("Doe", "John", Person.MALE, ...);
// assuming Employee extends Role
Employee e = (Employee)p.addRole(Employee.class);
由于角色类也实现了个人界面,我也可以这样做:
// assuming Parent extends Role
Parent parent = new Parent((PersonImpl)p);
e.addRole(Parent.class);
e.getDateOfBirth(); // handled by the decorated person class
// assuming Manager extends Employee extends Role
Manager m = (Manager)p.getRole(Manager);
if (m.hasRole(Employee.class) {
// true since Manager derives from Employee
}
的问题,我有是:
(a)是本实施不必要的复杂性,如果这样会怎样是一个更简单的方法?请注意,这进入了一个非平凡的业务应用程序,而不是一个kiddy项目,我认为角色子类化对于员工,经理等情况下的行为很重要。
(b)如何映射此在JPA /休眠?
(c)它可以被映射,所以我也可以利用Seam身份管理? (我的角色定义显然不像Seam's)
(d)如果我使用每个子类的继承类型(InheritanceType.JOINED)映射策略,我将PersonImpl映射为PERSONS和RoleImpl作为ROLES表,并映射RoleImpl的每个子类(如Employee和Parent)作为EMPLOYEES和PARENTS自己的表。
我将不得不(对角色的集合中PersonImpl的)人员和角色之间的一个@ManyToMany关系,联接表PERSON_ROLES。
现在的问题是,雇员和父母表等只有ROLE_ID引用,因为继承映射策略显然认为它们是角色(ROLES)的扩展,而我需要它们作为PERSON_ROLES的附录,并且需要USER_ID + ROLE_ID键被正确解析,或至少USER_ID。
我宁愿一个规范化的数据库,因为它依赖于额外的连接而不是一个非规范化的数据库,而这个数据库很难维护并且可能会聚集大量未使用和不相关的字段,这就是为什么我认为每个子类的表是要走的路。
或者在此场景中带有鉴别器列OK(从数据库维护角度看)的每个类的层次结构(InheritanceType.SINGLE_TABLE)?请注意,某些角色可能会有几十个属性/字段。 (e)这种设计有更好的选择吗?
非常感谢任何想法/建议。
如果每个角色对象都适用于单人对象,如代码所示,那么为什么人和角色之间存在@ManyToMany关系?是不是@OneToMany? – 2010-07-18 18:28:16
一个人可能有多个角色。每个角色可能有多个人。我认为亚瑟在@OneToMany的一面和@ManyToOne在另一面的观点可能有一些优点。必须检查... – 2010-07-19 06:28:41