Robe Elckers
Robe Elckers

Reputation: 977

JPA Inheritance mapping multiple implementations

I have a problem with JPA inheritance. See my entities below. I have a Person that can be in either a House or a Car, never at the same time of course. Both Car and House implement the PersonHoldable interface. I know I cannot map an Entity directly to an interface.

This is my model:

@Entity
public class Person{
  private PersonHoldable personHoldable; // either a Car or a House

  // This does not work of course because it's an interface
  // This would be the way to link objects without taking JPA into consideration.
  @OneToOne 
  public PersonHoldable getPersonHoldable() {
    return this.personHoldable;
  }

  public void setPersonHoldable(PersonHoldable personHoldable) {
    this.personHoldable = personHoldable;
  }
}

@Entity
public class Car implements PersonHoldable{}

@Entity
public class House implements PersonHoldable{}

public interface PersonHoldable{}

How can I map this correctly in JPA taking the following into consideration?

  1. I tried @MappedSuperclass on an abstract implementation of PersonHoldable. Although it will work for this particular setup, the problem with this is that Car and House in reality implement more interfaces. And they are mapped to other entities as well.
  2. The Person could have a property for every possible PersonHoldable, so in this case it could have a getCar() and getHouse() property. That does not seem very flexible to me. If I would add a Bike implementation of the PersonHoldable I would have to change my Person class.
  3. I can map the other way around, so having a OneToOne relation only on the PersonHoldable implementation side. This would mean adding a getPerson() property to the PersonHoldable. But then it's not very easy from a Person perspective to see what PersonHoldable it is linked to.
  4. I'm using default JPA, so no Hibernate specific tags if possible.

If this is not possible with default JPA, what would be best practice in this case?

Upvotes: 0

Views: 523

Answers (1)

Jeff
Jeff

Reputation: 3707

A slight variation on your second point would be to make Person have an inheritance type and implement a CarPerson and HousePerson (and later a BikePerson) whose whole purpose is to define the specific join relationship to a specific PersonHolder implementation. That keeps the relationship intact and more easily queryable from the Person side.

@Inheritance(strategy = JOINED)
@DiscriminatorColumn(name="holdableType", discriminatorType=CHAR, length=1)
@Entity
public class Person {
    // common fields
}

@Entity
@DiscriminatorValue("C")
public class CarPerson extends Person {
    @OneToOne
    private Car car;
}

@Entity
@DiscriminatorValue("H")
public class HousePerson extends Person {
    @OneToOne
    private House house;
}

Upvotes: 1

Related Questions