JPA:多态关联和连接表

问题描述 投票:1回答:2

我是Hibernate和JPA的新手。我有一个Identity类,它与EntityInformation有一对一的关系,它被子类化为PersonalInformation或CompanyInformation。

我正在尝试使用Joined表策略来保持DRY,以便数据库中的基本EntityInformation表具有公共字段,而PersonalInformation和CompanyInformation表仅具有特定于类的字段

当我使用“公司”类型创建标识时,我想为该标识创建一个CompanyInformation。我遇到的问题是,当我创建一个Identity时,EntityInformation是持久的,但不是Personal / CompanyInformation。

这可能吗?我觉得我缺少某些东西或者需要以不同的方式对事物进行建模。任何帮助将不胜感激!


这是我的Identity类:

@Entity
@Table(name = "identities")

public class Identity {

  @NotNull
  @Enumerated(EnumType.STRING)
  // type is either Personal or Company
  private IdentityType type;

  @NotNull
  @OneToOne(
    mappedBy = "identity", cascade = CascadeType.ALL, orphanRemoval = true, optional = false)

  private EntityInformation entityInformation;
  ...
}

EntityInformation类:

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = "entity_informations")

public class EntityInformation {

  @NotNull private Boolean hasTaxPayerId;

  @OneToOne(optional = false)
  @JoinColumn(name = "identity_id", nullable = false)
  private Identity identity;
  ...    
}

个人信息类:

public class PersonalInformation extends EntityInformation{

  @NotBlank private String firstName;

  @NotBlank private String lastName;

  private String middleName;
  ...
}

公司信息类:

public class CompanyInformation extends EntityInformation{

  @NotBlank private String name;
  ...
}
java hibernate jpa
2个回答
1
投票

你的身份表有点令人困惑。它与实体具有一对一的关系,并指定实体类型。在设计的这一点上,最好对模式进行非规范化并将类型保留在实体中。

优点:更好的性能(不是额外的连接),清晰度和级联问题的开销更少。

您可以在EntityInformation中添加具有类型的新字段,并在子实体中定义(如果需要)。


0
投票

设计看起来很好,除了我没有看到ids。你应该删除optional = false上的Identity。该属性仅用于检索,因为EntityInformation是关系的所有者,并且没有任何内容放在Identity模式中。它导致鸡和蛋问题b / c你不能创建两个新实体并将它们保存在同一个事务中b / c也不能为null但是必须先保存一个。我测试了它,它为我保持EntityInformationCorporateInformation

@Entity
public class Identity {
    @Id @GeneratedValue
    private Long id;

    @OneToOne(mappedBy = "identity", cascade = CascadeType.ALL, orphanRemoval = true)
    private InformationBase information;

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public abstract class InformationBase {
    @Id @GeneratedValue
    private Long id;

    @OneToOne(optional = false)
    @JoinColumn(name = "identity_id", nullable = false)
    private Identity identity;

@Entity
public class CorporateInformation extends InformationBase {

并使用它:

tx.begin();

Identity identity = new Identity();
CorporateInformation corporateInformation = new CorporateInformation();
corporateInformation.setIdentity(identity);
em.persist(identity);
em.persist(corporateInformation);

tx.commit();

在日志中显示

Hibernate: create table CorporateInformation (id bigint not null, primary key (id))
Hibernate: create table Identity (id bigint not null, primary key (id))
Hibernate: create table InformationBase (id bigint not null, identity_id bigint not null, primary key (id))
Hibernate: create table PersonalInformation (id bigint not null, primary key (id))
Hibernate: alter table InformationBase drop constraint if exists UK_s2ny1w2e3fpckgv97n4bhe49h
Hibernate: alter table InformationBase add constraint UK_s2ny1w2e3fpckgv97n4bhe49h unique (identity_id)
Hibernate: create sequence hibernate_sequence start with 1 increment by 1
Hibernate: alter table CorporateInformation add constraint FKq69d75va3x785scp4iki8kprs foreign key (id) references InformationBase
Hibernate: alter table InformationBase add constraint FK9g3vjjvp7ohn3dfirh6u8mwrx foreign key (identity_id) references Identity
Hibernate: alter table PersonalInformation add constraint FK6muqauf869dw0x9jb7jlhcpwo foreign key (id) references InformationBase
Hibernate: call next value for hibernate_sequence
Hibernate: call next value for hibernate_sequence
Hibernate: insert into Identity (id) values (?)
Hibernate: insert into InformationBase (identity_id, id) values (?, ?)
Hibernate: insert into CorporateInformation (id) values (?)
© www.soinside.com 2019 - 2024. All rights reserved.