I am trying to persist an object that has a many-to-many relationship with other objects already persisted.
Here is my persisted object (they are already persisted i
The exception comes as hibernate trying to persist associated products when you save reservation. Persisting the products is only success if they have no id because id of Product is annotated
@GeneratedValue(strategy=GenerationType.AUTO)
But you got products from repository and ids are not null.
There 2 options to resolve your issue:
(cascade = CascadeType.ALL)
on products of Reservation@GeneratedValue(strategy=GenerationType.AUTO)
on id of ProductI had the same problem and solved it by removing the cascade = CascadeType.PERSIST
.
In your case you use CascadeType.ALL
, which is equivalent to also using the PERSIST, according to the documentation:
Defines the set of cascadable operations that are propagated to the associated entity. The value cascade=ALL is equivalent to cascade={PERSIST, MERGE, REMOVE, REFRESH, DETACH}.
It means when you try to save the reservation on reservationDAO.save(reservation)
it will also try to persist the associated Product object. But this object is not attached to this session. So the error occur.
Remove @ CascadeType.ALL in the @ManytoMany relation, this worked for me.
You need to ensure both side of the relationship are properly maintained in your code.
Update Reservation as below and then add the corresponding methods to Product.
@Entity
@Table(name = "RESERVATION")
public class Reservation {
private int reservationId;
private Set<Product> products = new HashSet<Product>(0);
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public int getReservationId() {
return reservationId;
}
public void setReservationId(int reservationId) {
this.reservationId = reservationId;
}
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinTable(name = "product_reservation", joinColumns = { @JoinColumn(name = "reservationId", nullable = false, updatable = false) }, inverseJoinColumns = { @JoinColumn(name = "productId",
nullable = false, updatable = false) })
public Set<Product> getProducts() {
//force clients through our add and remove methods
return Collections.unmodifiableSet(products);
}
public void addProduct(Product product){
//avoid circular calls : assumes equals and hashcode implemented
if(! products.contains(product){
products.add(product);
//add method to Product : sets 'other side' of association
product.addReservation(this);
}
}
public void removeProduct(Product product){
//avoid circular calls: assumes equals and hashcode implemented:
if(product.contains(product){
products.remove(product);
//add method to Product: set 'other side' of association:
product.removeReservation(this);
}
}
}
And in Products:
public void addReservation(Reservation reservation){
//assumes equals and hashcode implemented: avoid circular calls
if(! reservations.contains(reservation){
reservations.add(reservation);
//add method to Product : sets 'other side' of association
reservation.addProduct(this);
}
}
public void removeReservation(Reservation reservation){
//assumes equals and hashcode implemented: avoid circular calls
if(! reservations.contains(reservation){
reservations.remove(reservation);
//add method to Product : sets 'other side' of association
reservation.reomveProduct(this);
}
}
Now you should be able to call save on either Product or Reservation and everything should work as expected.
entityManager.merge()
is a good option. It will merge the detached objects in the session. No need to change any cascadeType.
I have a feeling that your annotations are slightly incorrect. Not by much though, have a look at Example 7.24 here and see if it matches your annotations. Ignore the Collection
datatype though, as you shouldn't have any problems using a Set
. I notice that you are missing a cascade=CascadeType.ALL
on your Product
collection, but I can't work out if that is the problem or not.
What the actual exception is saying is that your Product
object(s) haven't actually been saved when its trying to save the collection of Product
's. That's why I think its a problem with your annotations.
Try it out and let me know if you get anywhere.