繁体   English   中英

JPA(Hibernate支持的)Maker-Checker多层继承

[英]JPA (Hibernate-backed) Maker-Checker Multi-Level Inheritance

我用于实施maker-checker方案的策略是通过使用多个表。 当前,我正在使用Hibernate 4.2(注释)。 以下是我要实现的方案。 但是,我在多级继承方面遇到问题。

基本思想是有两个表( pendingapproved )。 当发生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不是PolicyApproved不是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类,可以将MakerChecker重用于多个有效负载。

@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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM