Reputation: 4305
I am currently using Hibernate in a project and I am having trouble setting up a Many to Many relationship. I think my issue is related to the Cascade types.
The scenario is we have an advert and each advert can have many tags but each tag can be related to many adverts. The ManyToMany annotation of the advert entity is:
@ManyToMany(fetch = FetchType.LAZY, cascade = { CascadeType.MERGE, CascadeType.DETACH, CascadeType.REFRESH })
@JoinTable(name = "adMediaAdvertiserTag",
joinColumns = { @JoinColumn(name = "adMediaId") },
inverseJoinColumns = { @JoinColumn(name = "advertiserTagId") })
And the ManyToMany mapping on the tag entity is:
@ManyToMany(mappedBy = "advertiserTags", fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE })
I am seeing two different errors depending on the configuration of the cascade types and if the tag already exists in the database.
If the cascade type on the advert doesn't include PERSIST and the tag doesn't already exist then we get this exception:
TransientObjectException: object references an unsaved transient instance
And if the cascade type on the advert does include PERSIST and the tag does already exist we get:
PersistentObjectException: detached entity passed to persist
The only way I can get this working is not have PERSIST as a cascade type but loop through each tag and save them to the session.
Is this the correct approach? Is there a way that hibernate could automatically handle this for me?
Let me know if this isn't clear or you need any more information.
UPDATE
I am saving the objects using a service that uses the save method the CrudRepository object of the springframework. There is a lot of code so I can't really post it all.
I am currently not calling any merge or persist method for any object I am trying to save. I was under the impression Hibernate would handle that sort of thing for me.
Upvotes: 1
Views: 2303
Reputation: 6144
Can you please add the code you are using to persist your Advert and Tag objects. I tested with the following code (which I believe similar to yours) and it works:
User user = new User();
Role role = new Role();
role.setId("TEST_ROLE");
user.getRoles().add(role);
entityManager.persist(user);
User user2 = new User();
user2.getRoles().add(role);
entityManager.persist(user2);
System.out.println(user2.getId());
in User I have:
@ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
@JoinTable(name = "user_roles",
joinColumns = {@JoinColumn(name = "user_id", nullable = false, updatable = true)},
inverseJoinColumns = {@JoinColumn(name = "role_id", nullable = false, updatable = true)})
protected List<Role> roles = new ArrayList<>();
and in Role I have:
@ManyToMany(mappedBy="roles")
protected List<User> users;
Upvotes: 1