Pickeroll
Pickeroll

Reputation: 978

JPA mapping FK of different types

As now my approach to create a simple one to many relation with JPA has been this:

Entity A Table

@Table(name = "EntityA", schema = "schema")
public class EntityA {

  @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Integer id;

 @OneToMany(mappedBy = "EntityA", cascade = {CascadeType.ALL}, orphanRemoval = true)
    private List<EntityB> entitiesB;
}

Entity B Table

@Table(name = "EntityB", schema = "schema")
public class EntityB {

  @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "id")
    private Integer id;

  @ManyToOne
   @JoinColumn(name = "entityA_id")
   private EntityA entityA;   
}

Now another table comes into play, and the ManyToOne column in EntityB could be of type EntityA or type EntityC, my first guess was to use generics but I stumbled in the same problem of this post and I have some difficulties in following the attached documentation.

Is there a more simple approach to solve this problem ?

I was thinking about declaring the manyToOne column as Integer, considering that both EntityA and EntityC have an unique auto-generated Integer id, but I don't know if this is a possible approach and someway I would like to follow some consistency in all my application.

Upvotes: 0

Views: 256

Answers (1)

Thorben Janssen
Thorben Janssen

Reputation: 3275

You can solve this in 2 ways:

  1. You model 2 separate one-to-many associations if EntityB and EntityC are independent of each other. (This is the most common approach)
  2. If EntityB and EntityC share a superclass, you can model and map the inheritance hierarchy and use a polymorphic association mapping.

Option 1: 2 Separate Associations

This approach is the most common one because it's easy to implement and very flexible. You should use it if EntityB and EntityC don't belong to the same inheritance hierarchy.

@Entity
public class EntityA {

   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   private Integer id;

   @OneToMany(mappedBy = "entityA", cascade = {CascadeType.ALL}, orphanRemoval = true)
   private List<EntityB> entitiesB;

   @OneToMany(mappedBy = "entityA", cascade = {CascadeType.ALL}, orphanRemoval = true)
   private List<EntityC> entitiesC;

   // getter and setter methods ...
}

I kept the cascade and orphanRemoval settings you used in your initial mapping. Please double-check them before you deploy this to production. Both should only be used for parent-child associations. Especially CascadeType.REMOVE, which is included in CascadeType.ALL, can have some negative side effects.

Option 2: 1 Polymorphic Association

If EntityB and EntityC belong to the same inheritance hierarchy and you use JPA's inheritance mapping InheritanceType.JOINED or InheritanceType.SINGLE_TABLE, you can use a polymorphic association mapping.

(Note: InheritanceType.TABLE_PER_CLASS also supports polymorphic associations, but the queries get very complex, which often causes performance issues and should be avoided.)

After you modeled your inheritance hierarchy, you can define an association to the shared superclass. This association includes all subclasses. When you fetch this association from the database, your persistence provider instantiates the correct subclass for each record and returns it as a collection of the superclass.

@Entity
public class EntityA {

   @Id
   @GeneratedValue(strategy = GenerationType.AUTO)
   private Integer id;

   @OneToMany(mappedBy = "entityA", cascade = {CascadeType.ALL}, orphanRemoval = true)
   private List<SuperEntity> superEntities;

   // getter and setter methods ...
}

Upvotes: 2

Related Questions