Many to many with just a list of domain value object id

For the purpose of simplifying the problem, consider that I have a Location aggregate, which can exist independently. Here’s an example:

class LocationId {
   String value;
}

class Location {
   LocationId value;
   // other attributes
}

Also a Person class, which can be associated with zero or more Location instances. In a pure object-oriented model, I would have something like this:

class PersonId {
   String value;
}

class Person {
   PersonId id;
   List<LocationId> locations;

   void addLocation(Location location) {
      // perform checks on location
      // associate location id with person
   }

   void removeLocation(Location location) {
      // perform checks on location
      // disassociate location id from person
   }
}

To map these models to the database, I would use the following structure:

  • location table with a primary key (id)
  • person table with a primary key (id)
  • person_location table (with person_id and location_id as foreign keys to person and location)

My question is
How can I map the locations property to the database without modifying my domain model classes, just by adding annotations?

  • The closest I got was using this approach.
@ElementCollection
@CollectionTable(
  name = "person_location",
  joinColumns = @JoinColumn(name = "person_id")
)
@AttributeOverride(name = "value", column = @Column(name = "location_id"))

However, when generating the tables, the foreign key is only created from person_location.person_id to person.id, missing the foreign key from person_location.location_id to location.id.

Hibernate:
    alter table if exists person_location
       add constraint FK6ftdgrcrspx1gl3qfvmsdtqru        
       foreign key (person_id)
       references person
  • Another possibile solution would be to have the entire Location inside Person. However, in my domain model I just don’t need to have the entire Location inside Person. They are two different aggregates and ideally they should be related by Id and unilaterally.
@ManyToMany
@JoinTable(
        name = "person_location",
        joinColumns = @JoinColumn(name = "location_id"),
        inverseJoinColumns = @JoinColumn(name = "person_id"))
private List<Location> locations;

Github repository Just run and check application log startup

You can create a separate entity mapped to the same table e.g. LocationReference which consists of just the id. Then you can map locations to that entity instead and Hibernate ORM will create an FK constraint for you.