Java JPA(支持Hibernate的)Maker Checker多级继承
我实施maker checker场景的策略是使用多个表。目前,我正在使用Hibernate4.2(注释)。下面的场景是我想要实现的。然而,我在多级继承方面遇到了问题 基本思想是有两个表(Java JPA(支持Hibernate的)Maker Checker多级继承,java,hibernate,jpa,Java,Hibernate,Jpa,我实施maker checker场景的策略是使用多个表。目前,我正在使用Hibernate4.2(注释)。下面的场景是我想要实现的。然而,我在多级继承方面遇到了问题 基本思想是有两个表(pending和approved)。当发生add()时,条目将插入到pending表中。当该条目被批准时,它将从待定表中删除,并插入已批准表中 Policy (the policy) | + -- Pending (maker information) | + -- Approved (che
pending
和approved
)。当发生add()
时,条目将插入到pending
表中。当该条目被批准时,它将从待定
表中删除,并插入已批准
表中
Policy (the policy)
|
+ -- Pending (maker information)
|
+ -- Approved (checker information)
因此,classPolicy
是定义策略所需字段的类。为了缩短此帖子,不显示字段
@MappedSuperclass
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) // problem
public abstract class Policy { ... }
Pending
类用于等待批准的新添加的策略
,它包含制造商/加工商的信息
@Entity
@Table(name = "pending")
public class Pending extends Policy {
@Column(name = "adder", ...)
private String adder;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "time_added", ...)
private Date timeAdded;
}
Approved
类用于已批准的实体,除了来自Pending
类的信息外,它还包含关于批准者的其他信息
@Entity
@Table(name = "approved")
public class Approved extends Pending {
@Column(name = "approver", ...)
private String approver;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "time_approved", ...)
private Date timeApproved;
}
@Entity
@Table(name = "approved")
public class Approved extends Policy {
@Column(name = "adder", ...)
private String adder;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "time_added", ...)
private Date timeAdded;
@Column(name = "approver", ...)
private String approver;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "time_approved", ...)
private Date timeApproved;
}
@Embedabble
public class Maker {
@Column(name="maker_id", ...)
private String makerId;
@Temporal(TemporalType.TIMESTAMP)
@Column(name="time_added", ...)
private Date timeAdded;
}
@Embedabble
public class Checker {
@Column(name="checker_id", ...)
private String makerId;
@Temporal(TemporalType.TIMESTAMP)
@Column(name="time_approved", ...)
private Date timeApproved;
}
我的第一个想法是尝试TABLE\u PER\u CLASS
。但是,它导致了以下运行时错误:org.hibernate.MappingException:无法将标识列键生成与映射用于:…
。解决方案是将基类@GeneratedValue(strategy=GenerationType.IDENTITY)
修改为@GeneratedValue(strategy=GenerationType.TABLE)
。但是,修改该类超出了我的范围,因为它是跨多个项目共享的
只是为了好玩,我尝试了另外两种策略。显然,SINGLE_TABLE
生成了一个表,其中有一个额外的列DTYPE
。不是我们想要的<代码>合并产生了两个表,但是已批准的
表有一个外键指向待定的
表。由于我们希望从待定
表中删除一个条目,并将其移动到已批准的
表中,因此这对我们不起作用
目前,我的解决方案如下,基本上是将代码从Pending
类复制粘贴到Approved
类中
@Entity
@Table(name = "approved")
public class Approved extends Pending {
@Column(name = "approver", ...)
private String approver;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "time_approved", ...)
private Date timeApproved;
}
@Entity
@Table(name = "approved")
public class Approved extends Policy {
@Column(name = "adder", ...)
private String adder;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "time_added", ...)
private Date timeAdded;
@Column(name = "approver", ...)
private String approver;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "time_approved", ...)
private Date timeApproved;
}
@Embedabble
public class Maker {
@Column(name="maker_id", ...)
private String makerId;
@Temporal(TemporalType.TIMESTAMP)
@Column(name="time_added", ...)
private Date timeAdded;
}
@Embedabble
public class Checker {
@Column(name="checker_id", ...)
private String makerId;
@Temporal(TemporalType.TIMESTAMP)
@Column(name="time_approved", ...)
private Date timeApproved;
}
这个解决方案似乎违反直觉,因为它复制了代码。是否有一种解决方案不需要代码复制,并保持maker checker流程目前的工作方式?对此,我将使用不同的方法。我假设
Policy
是您的实体-承载真正有效负载的实体。您想向它添加一些元数据。在我看来,继承权并不适合这种情况。待决
不是策略
,已批准
不是待决
我将元数据建模为独立的、不相关的实体,并创建与有效负载实体的1-1关系,而不是继承。或多对一,如果您需要多个批准
这样,您就有了更好的解耦数据模型和更规范化的数据库结构。这给了你更多的灵活性。您可以有一个或多个审批,在不更改有效负载实体的情况下更改审批模型,并且可以有一个更集中的有效负载实体,不受元数据的影响
实体可以如下所示:
@Entity
public class Policy{
@OneToOne
private Creation creation;
@OneToMany(mappedBy="policy")
private List<Approval> approvals;
...
}
批准:
@Entity
public class Approval {
@ManyToOne
private Policy policy;
private String approver;
@Temporal(TemporalType.TIMESTAMP)
private Date approvedAt;
..
}
在试验了@kostja建议的方法之后,我得出了以下解决方案 maker类封装了与maker相关的信息,maker也是一个
@embedded
类
@Entity
@Table(name = "approved")
public class Approved extends Pending {
@Column(name = "approver", ...)
private String approver;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "time_approved", ...)
private Date timeApproved;
}
@Entity
@Table(name = "approved")
public class Approved extends Policy {
@Column(name = "adder", ...)
private String adder;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "time_added", ...)
private Date timeAdded;
@Column(name = "approver", ...)
private String approver;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "time_approved", ...)
private Date timeApproved;
}
@Embedabble
public class Maker {
@Column(name="maker_id", ...)
private String makerId;
@Temporal(TemporalType.TIMESTAMP)
@Column(name="time_added", ...)
private Date timeAdded;
}
@Embedabble
public class Checker {
@Column(name="checker_id", ...)
private String makerId;
@Temporal(TemporalType.TIMESTAMP)
@Column(name="time_approved", ...)
private Date timeApproved;
}
类似地,checker类还封装了与checker相关的信息,checker也是一个@embedded
类
@Entity
@Table(name = "approved")
public class Approved extends Pending {
@Column(name = "approver", ...)
private String approver;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "time_approved", ...)
private Date timeApproved;
}
@Entity
@Table(name = "approved")
public class Approved extends Policy {
@Column(name = "adder", ...)
private String adder;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "time_added", ...)
private Date timeAdded;
@Column(name = "approver", ...)
private String approver;
@Temporal(TemporalType.TIMESTAMP)
@Column(name = "time_approved", ...)
private Date timeApproved;
}
@Embedabble
public class Maker {
@Column(name="maker_id", ...)
private String makerId;
@Temporal(TemporalType.TIMESTAMP)
@Column(name="time_added", ...)
private Date timeAdded;
}
@Embedabble
public class Checker {
@Column(name="checker_id", ...)
private String makerId;
@Temporal(TemporalType.TIMESTAMP)
@Column(name="time_approved", ...)
private Date timeApproved;
}
有效负载是一个@可嵌入的
类。通过将有效负载设置为@可嵌入类,可以将生成器
和检查器
重新用于多个有效负载
@Embeddable
public class Payload { ... }
例如,给定两个需要maker/checker的不同有效载荷。其中一个有效负载需要2个检查器
@Embeddable
public class PayloadA { ... }
@Embeddable
public class PayloadB { ... }
然后我们为PayloadA
定义以下两个表
@Entity
@Table("a_pending")
public class PendingA {
@Embedded
private PayloadA payload;
@Embedded
private Maker maker;
}
@Entity
@Table("a_approved")
public class ApprovedA {
@Embedded
private PayloadA payload;
@Embedded
private Maker maker;
@Embedded
private Checker checker;
}
同样,对于PayloadB
定义两个表。而PayloadB
需要两个checker
@Entity
@Table("b_pending")
public class PendingB {
@Embedded
private PayloadB payload;
@Embedded
private Maker maker;
}
@Entity
@Table("b_approved")
public class ApprovedB {
@Embedded
private PayloadB payload;
@Embedded
private Maker maker;
@Embedded
@AttributeOverrides(value = {
@AttributeOverride(name="checkerId",column="checker1_id"),
@AttributeOverride(name="timeApproved",column="checker1_time_approved"),
})
private Checker checker1;
@Embedded
@AttributeOverrides(value = {
@AttributeOverride(name="checkerId",column="checker2_id"),
@AttributeOverride(name="timeApproved",column="checker2_time_approved"),
})
private Checker checker2;
}
我希望这个解决方案应该足够通用和灵活。这种层次结构似乎不足以满足“Is-a”规则。已批准的内容不再待定。这可能是一个命名问题。我将创建与实体具有1-1关系的不相关的创建
和批准
类。“没有一个按描述工作”是什么意思?谢谢。我喜欢你的方法。不过,我还有几个问题要问。我选择表方法的原因是,当某个东西被批准时(不管批准链如何),它会进入自己的表中。这意味着批准的项目(如政策)将生效(在指定时间)。其他项目可以从批准的表中读取并相应地采取行动。有人会如何区分待批准和已批准?