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.
This is the database :
Any idea what I am missing?
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