javadatabasehibernatespring-data-jpahibernate-mapping

Hibernate: OneToMany and OneToOne for two classes in SINGLE_TABLE_STRATEGY


I have a parent class: Person and two child classes: Hunter and Policeman. A Hunter can have several Dog, and a Policeman can only have one Dog. It's a unidirectional relationship, the Dog entity only has an attribute breed:

@Entity
@Inheritance(strategy = InheritanceType.SINGLE_TABLE)
public class Person {
  private String name;

and child classes:

@Entity
public class Hunter {
  private String forest;

  @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
  @JoinColumn(name = "hunter_id", referencedColumnName = "id")
  private Set<Dog> dogs;

@Entity
public class Policeman {
  private String city;

  @OneToOne(cascade = CascadeType.ALL)
  @JoinColumn(name = "dog_id")
  private Dog dog;

It generates table structure like this:

person

id, name, forest, city, dog_id, person_type

dog:

id, breed, hunter_id

So essentially because the Policeman only has one day, the dog's id FK is put in person table. It would be null for rows that relate to a Hunter.

And because a Hunter has several dogs, the hunter's ID is put as a FK in the dog table.

I picked this approach, because it provides compile-time checks - I can't possibly associate more than one dog with a Policeman.

However, I've been wondering if it's a right approach and if it would have been better to just have person_id FK in the dog table and ensure that the Policeman only has one dog in the service classes?


Solution

  • I picked this approach, because it provides compile-time checks - I can't possibly associate more than one dog with a Policeman.

    That's true, but your approach allows the same dog to be associated with both a Policeman and a Hunter at the same time.

    However, I've been wondering if it's a right approach and if it would have been better to just have person_id FK in the dog table and ensure that the Policeman only has one dog in the service classes?

    Yes, I would model the dog's associated person consistently with respect to the dog, regardless of the specific type of person. There are both practical and design reasons for this. For example, it prevents having one dog with two different people associated.

    And if you wanted to do, you could still model Policeman with a one-to-one relationship; it just needs to be owned by the Dog side. That does leave room for inconsistency in the DB in the form of multiple dog records all associated with one policeman, but that's more or less a break-even: you're trading one means of inconsistency for another.