简体   繁体   English

JPA:多态关联和连接表

[英]JPA: Polymorphic association and Joined table

I'm fairly new to Hibernate and JPA.我对 Hibernate 和 JPA 还很陌生。 I have an Identity class that has a one to one relationship to an EntityInformation, which is subclassed as either a PersonalInformation or a CompanyInformation.我有一个与 EntityInformation 有一对一关系的 Identity 类,它被子类为 PersonalInformation 或 CompanyInformation。

I'm trying to use the Joined table strategy to stay DRY so that the base EntityInformation table in the database has common fields while the PersonalInformation and CompanyInformation tables only have class-specific fields我正在尝试使用联接表策略来保持 DRY,以便数据库中的基本 EntityInformation 表具有公共字段,而 PersonalInformation 和 CompanyInformation 表仅具有特定于类的字段

When I create an Identity with a "Company" type, I want to create a CompanyInformation for that Identity.当我创建一个“公司”类型的身份时,我想为该身份创建一个 CompanyInformation。 The issue I'm having is that when I create an Identity, an EntityInformation is persisted but not a Personal/CompanyInformation.我遇到的问题是,当我创建身份时,会保留一个实体信息,但不会保留个人/公司信息。

Is this possible?这可能吗? I feel like I'm missing something or need to model things differently.我觉得我错过了一些东西或需要以不同的方式建模。 Any help would be greatly appreciated!任何帮助将不胜感激!


Here is my Identity class:这是我的身份类:

@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 class:实体信息类:

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

PersonalInformation class:个人信息类:

public class PersonalInformation extends EntityInformation{

  @NotBlank private String firstName;

  @NotBlank private String lastName;

  private String middleName;
  ...
}

CompanyInformation class:公司信息类:

public class CompanyInformation extends EntityInformation{

  @NotBlank private String name;
  ...
}

Your identity table is a little bit confusing.你的身份表有点混乱。 It has a one-one relationship with an entity and specifies the entity type.它与实体具有一一关系并指定实体类型。 At this point of design, it is better to denormalize your schema and keep the types in the entities.在设计的这一点上,最好对架构进行非规范化并将类型保留在实体中。

Advantages : better performance (not extra join), clarity and less overhead with the cascade issues.优点:更好的性能(不是额外的连接)、清晰和更少的级联问题开销。

You can add a new field in EntityInformation with the type and define in it in the children entities (if you need it).您可以在 EntityInformation 中添加一个具有类型的新字段,并在子实体中定义它(如果需要)。

Looks fine for design except I don't see ids .除了我没有看到ids之外,设计看起来不错。 You should remove optional = false on Identity .您应该在Identity上删除optional = false That property is only there for retrieval since the EntityInformation is the owner of the relationship and nothing is put in the Identity schema for that.该属性仅用于检索,因为EntityInformation是关系的所有者,并且没有为此放入Identity架构中。 It causes a chicken and egg problem b/c you can't create both new entities and save them in the same transaction b/c neither can be null but one has to be saved before the other.它会导致鸡和蛋的问题 b/c 你不能创建两个新实体并将它们保存在同一个事务中 b/c 都不能为空但一个必须在另一个之前保存。 I tested it and it persisted both EntityInformation and CorporateInformation for me.我对其进行了测试,它为我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 {

and to use it:并使用它:

tx.begin();

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

tx.commit();

shows in logs在日志中显示

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 (?)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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