javaspringspring-datacrudcrud-repository

Spring not saving many-to-many mapping in DB


I have 2 entities. An Appointment and an Item. They are both independent and we can have multiple items, in multiple appointments.

The Appointment class:

@Entity(name = "Appointment")
@Table(name = "appointment")
public class Appointment
{
    @Id
    @JsonProperty("appointment_id")
    @Column(name = "appointment_id", nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @JsonProperty("date")
    private Date startingTimestamp;

    @ManyToMany(mappedBy = "appointment",
        cascade = CascadeType.ALL)
    private List<Item> collectionOfItems;

    @JsonProperty("duration")
    private int duration;

    @JsonProperty("state")
    private AppoitmentState state;

    @ManyToOne
    @JsonBackReference
    @JoinColumn(name="user_appointment_owner_id", nullable = false)
    @JsonProperty("user_owner")
    private User user;

and the Item class :

@Entity
@Table(name = "item")
public class Item
{
    @Id
    @Column(name = "item_id", nullable = false)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long Id;

    @JsonProperty("name")
    private String name;

    @JsonProperty("duration")
    private int duration;

    @ManyToMany(targetEntity = Appointment.class,
        cascade = CascadeType.ALL)
    @JoinTable(name = "appointment_item", joinColumns = { @JoinColumn(name = "item_id") },
        inverseJoinColumns = { @JoinColumn(name = "appointment_id") })
    private List<Appointment> appointment;

    @ManyToMany
    @JsonProperty("set_of_professionals")
    @JsonIgnore
    private Set<Professional> professional;

    @JsonProperty("business_owning")
    private Long business_id;

Constructors, getters and setters are omitted here.

There is also a patch method inside the Appointment controller.

@RequestMapping(value = "appointment/{itemID}", method = RequestMethod.PATCH,  consumes = MediaType.APPLICATION_JSON_VALUE)
ResponseEntity<Appointment> addItem(@PathVariable Long itemID, @RequestBody ObjectNode appointment_id_str)
{
    Long appointment_id = appointment_id_str.get("appoitment_id").asLong();
    Optional<Appointment> targetAppoitment = appointmentService.findById(appointment_id);
    Optional<Item> addedItem = itemService.findById(itemID);
    if (targetAppoitment.isPresent() && addedItem.isPresent())
    {
        Appointment appoitmentInDB = targetAppoitment.get();
        appoitmentInDB.addItem(addedItem.get());
        Appointment savedAppointment = appointmentService.save(appoitmentInDB);
        return new ResponseEntity<>(savedAppointment, HttpStatus.CREATED);
    }
    return new ResponseEntity("", HttpStatus.INTERNAL_SERVER_ERROR);
}

Now although as seen in the debugger, an item has been added in appoitment's list, save will not flash the change into the database.

enter image description here

This is the database :

Database

Any idea what I am missing?


Solution

  • It is because the Item class own's the relationship.

    If you have described the relationship inside the Appointment class and used mappedBy inside the Item class you wouldn't have this issue. This happens because Hibernate uses the class in which the relationship was defined in order to maintain it's associations.

    To fix this problem you should adjust you entities in the following way:

    class Appointment {
    
    ...
        
    @ManyToMany(targetEntity = Item.class,
            cascade = CascadeType.ALL)
        @JoinTable(name = "appointment_item", joinColumns = { @JoinColumn(name = "appointment_id") },
            inverseJoinColumns = { @JoinColumn(name = "item_id") })
        List<Item> collectionOfItems;
    
    ...
    
    }
    

    and

    class Item {
    
    ...
    
        @ManyToMany(mappedBy = "collectionOfItems",
            cascade = CascadeType.ALL)
        private List<Appointment> appoitment;
    
    ...
    
    }
    

    This question has already been answered on stackoverflow, link