Java JPA(支持Hibernate的)Maker Checker多级继承

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

我实施maker checker场景的策略是使用多个表。目前,我正在使用Hibernate4.2(注释)。下面的场景是我想要实现的。然而,我在多级继承方面遇到了问题

基本思想是有两个表(
pending
approved
)。当发生
add()
时,条目将插入到
pending
表中。当该条目被批准时,它将从
待定
表中删除,并插入
已批准
表中

Policy (the policy)
|
+ -- Pending (maker information)
     |
     + -- Approved (checker information)
因此,class
Policy
是定义策略所需字段的类。为了缩短此帖子,不显示字段

@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关系的不相关的
创建
批准
类。“没有一个按描述工作”是什么意思?谢谢。我喜欢你的方法。不过,我还有几个问题要问。我选择表方法的原因是,当某个东西被批准时(不管批准链如何),它会进入自己的表中。这意味着批准的项目(如政策)将生效(在指定时间)。其他项目可以从批准的表中读取并相应地采取行动。有人会如何区分待批准和已批准?