dognose
dognose

Reputation: 20889

Persisting multiple entities and their relations (Cascade.All / ManyToMany)

I need to create a bunch of objects programatically and persist them all. There are 1:n, 1:1 and n:n relations involved at the same time.

All relations are defined with CascadeType.All.

When I now create all the object instances and set their relations, only the first persist() operation will work. The others will fail with the message, that a detached entity has been passed to persist.

Example:

A a1 = new A();
A a2 = new A();
A a3 = new A();

CommonB = new B();
SpecialB = new B();

Set<B> set1 = new HashSet<B>();
set1.add(CommonB);
set1.add(SpecialB);

Set<B> set2 = new HashSet<B>();
set2.add(CommonB);

a1.setBs(set1);
a2.setBs(set2);
a3.setBs(set2);

Now, i'm using our dataservice to persist a1, a2 and a3. (It basically just calls persist() on the entitymanager)

The first attempt works well, Both, CommonB and SpecialB are persisted along with a1 (also the relations are created. However, when i try to persist a2, Hibernate says org.hibernate.PersistentObjectException: detached entity passed to persist: my.namespace.B

Classes look like this:

class A(){
    @ManyToMany(fetch = FetchType.EAGER, cascade = { CascadeType.ALL })
    @JoinTable
    private Set<B> bs;

    //get set
}

class B(){
    @ManyToMany(fetch = FetchType.EAGER, cascade = { CascadeType.ALL }, mappedBy = "bs")
    private Set<A> as;
}

The example has been stripped down, in fact there are multiple n:n relations between 5 entities.

--- update

I missed to add the "As" to the "Bs" Set as well:

CommonB.setAs(/* a1, a2, a3 */);
SpecialB.setAs(/* a1 */);

So, saying the complete relations are set on the object level. Shouldn't Cascade.All actually take care of persisting ALL objects within a certain relation bunch, whenever I save ONE of those objects?

If i give like em.persist(a1), shouldn't hibernate notice:

However that is not going to happen..

Upvotes: 0

Views: 1887

Answers (1)

Ean V
Ean V

Reputation: 5439

When you persist a1, it also persists the CommonB and sets id into that object. Persisting a2 will try to persist CommonB again while it has been persisted once. I assume your dataservice is Transactional, so after persisting a1 it closes TX and Hibernate's session then CommonB becomes a detached object. You need to reload(re-attach) CommonB when persisting a2 and a3.

Upvotes: 2

Related Questions