Search code examples
hibernatejpaspring-data-jpamany-to-many

Rows at other end of @ManyToMany are not being deleted


I have the following entities to model Hours of Operation ("HOOP") for freestanding storefronts and contact center queues.

I have the following entities:
Holiday, which defines a name and an observed date.

HolidayHOOP, which holds operating hours on a selected Holiday, with mapping like so:

@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "holiday_id")
private Holiday holiday;

HOOP, which defines the operating hours for Monday through Sunday, and holds a List as follows:

@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
@JoinTable(
          name = "hoop_holiday_hoop_mapping", 
          joinColumns = @JoinColumn(name = "hoop_id"), 
          inverseJoinColumns = @JoinColumn(name = "holiday_hoop_id"))
private List<HolidayHOOP> holidays = new ArrayList<>();

So, if I wanted to express the following: "The Sarasota office is open Mondays from 9 AM to 5 PM, and is closed on Christmas."

I would add a Holiday record for Christmas manually. I would then create an HOOP object for the Sarasota office and set the open and closed time. I would then create a HolidayHOOP object that references the Christmas Holiday, and add it to the holidays list on the HOOP object. Finally, I'd do a repository.save(hoop). My DB shows:

  1. The new HOOP
  2. The new HolidayHOOP
  3. A mapping of HOOP to HolidayHOOP via hoop_holiday_hoop_mapping.

However!

If I update my HOOP object and change the content of that list, such as adding/removing observed holidays, there are orphan HolidayHOOP records being left in the table. Furthermore, if I delete an HOOP entry outright, all of its HolidayHOOPs are being left behind.

Is it possible to annotate these types such that the HolidayHOOP records are pruned as the HOOP entries are changed? Or, is a manual cleanup of this data required due to the modeling of this solution?


Solution

  • A constraint I didn't mention is that I'm trying to manage both the HOOP and HolidayHOOP records via just manipulation of the HOOP data. In other words, I want to be able to CRUD HolidayHOOPs simply by manipulating the list on an HOOP and then doing a repository.save(hoop) or repository.delete(hoop) at the end. From an OO perspective, a single HOOP object will have one or more HolidayHOOPs that it thinks are unique, even if the data in the table appears to be redundant, i.e. different locations having the same Holiday hours. I solved my problem and accomplished this as follows:

    1.
    I changed the relationship from ManyToMany to OneToMany:

    @OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
    @JoinTable(
              name = "hoop_holiday_hoop_mapping", 
              joinColumns = @JoinColumn(name = "hoop_id"), 
              inverseJoinColumns = @JoinColumn(name = "holiday_hoop_id"))
    private List<HolidayHOOP> holidays = new ArrayList<>();
    

    Prior to performing a save of an existing HOOP object, I load the current record in the table and fill in all of the HolidayHOOP data that ISN'T changing. This latter step prevents PersistenceExceptions on the save operation.