[英]JPA (Hibernate-backed) Maker-Checker Multi-Level Inheritance
我用于实施maker-checker方案的策略是通过使用多个表。 当前,我正在使用Hibernate 4.2(注释)。 以下是我要实现的方案。 但是,我在多级继承方面遇到问题。
基本思想是有两个表( pending
和approved
)。 当发生add()
时,该条目将插入到pending
表中。 批准该条目后,将其从pending
表中删除并插入到approved
表中。
Policy (the policy)
|
+ -- Pending (maker information)
|
+ -- Approved (checker information)
因此, Policy
类是为策略定义必要字段的类。 为了使这篇文章简短,不显示字段。
@MappedSuperclass
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) // problem
public abstract class Policy { ... }
Pending
类用于等待批准的新添加的Policy
,并且具有有关制造者/添加者的信息。
@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;
}
我首先想到的是尝试TABLE_PER_CLASS
。 但是,它导致以下运行时错误: org.hibernate.MappingException: Cannot use identity column key generation with <union-subclass> mapping for: ...
解决方案是将基类@GeneratedValue(strategy = GenerationType.IDENTITY)
为@GeneratedValue(strategy = GenerationType.TABLE)
。 但是,修改该类超出了我的范围,因为它在多个项目中共享。
仅仅为了它,我尝试了另外两种策略。 显然, SINGLE_TABLE
了一个表,并带有一个额外的列DTYPE
。 不是我们想要的。 JOINED
产生了两个表,但已approved
表具有一个pending
表的外键。 由于我们想从pending
表中删除一个条目并将其移至approved
表,因此这对我们不起作用。
目前,我的解决方案如下,基本上是将代码从Pending
类复制并粘贴到Approved
类中。
@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;
}
该解决方案在重复代码时似乎违反直觉。 是否有一种解决方案不需要代码重复,并且可以使maker-checker流程保持当前的工作方式?
我将为此使用其他方法。 我认为Policy
是您的实体-承载真实有效负载的实体。 您想向其中添加一些元数据。 在我看来,继承似乎并不适合。 Pending
不是Policy
, Approved
不是Pending
。
代替继承,我将元数据建模为单独的不相关实体,并创建与有效负载实体的1-1关系。 或多对一(如果需要多个批准)。
这样,您将拥有更好的解耦数据模型和更规范的数据库结构。 这为您提供了更大的灵活性。 您可以具有单个或多个批准,可以在不更改有效负载实体的情况下更改批准模型,并可以使焦点更加集中的有效负载实体不受元数据的负担。
实体看起来像这样:
@Entity
public class Policy{
@OneToOne
private Creation creation;
@OneToMany(mappedBy="policy")
private List<Approval> approvals;
...
}
创建:
@Entity
public class Creation{
@OneToOne
private Policy policy;
private String creator;
@Temporal(TemporalType.TIMESTAMP)
private Date createdAt;
...
}
认证:
@Entity
public class Approval {
@ManyToOne
private Policy policy;
private String approver;
@Temporal(TemporalType.TIMESTAMP)
private Date approvedAt;
..
}
在尝试@kostja建议的方法之后,我得出了以下解决方案。
maker类封装了与制造商有关的信息,它也是@Embeddable
类。
@Embedabble
public class Maker {
@Column(name="maker_id", ...)
private String makerId;
@Temporal(TemporalType.TIMESTAMP)
@Column(name="time_added", ...)
private Date timeAdded;
}
类似地,检查器类还封装了与检查器有关的信息,它也是@Embeddable
类。
@Embedabble
public class Checker {
@Column(name="checker_id", ...)
private String makerId;
@Temporal(TemporalType.TIMESTAMP)
@Column(name="time_approved", ...)
private Date timeApproved;
}
有效负载是@Embeddable
类。 通过将有效负载@Embeddable
类,可以将Maker
和Checker
重用于多个有效负载。
@Embeddable
public class Payload { ... }
例如,给定需要制造者/检查者的两个不同的有效载荷。 有效载荷之一需要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
需要两个检查器。
@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;
}
我希望这个解决方案应该足够通用和灵活。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.