简体   繁体   中英

JPA: Polymorphic association and Joined table

I'm fairly new to Hibernate and 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.

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

When I create an Identity with a "Company" type, I want to create a CompanyInformation for that Identity. 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).

Looks fine for design except I don't see ids . You should remove optional = false on Identity . 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. 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. I tested it and it persisted both EntityInformation and CorporateInformation for me.

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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