EJB3: em.merge()

Hi,

I have a detached entity that I return to the application server

as a parameter. Before being able to work with this entity on the

server, I have to merge it, right?

Everywhere I look this is done simply by

@PersistenceContext

private EntityManager em;

em.merge(entity);

entity is now supposed to be attached to the database again.

But with me, this doesn't work! What I have to do is this:

@PersistenceContext

private EntityManager em;

entity = em.merge(entity);

Can someone confirm on this? I think I read this somewhere,

too, but can't remember where. JavaDoc also says that the

merge method has a return value:

"Returns: the instance that the state was merged to"

Thanks for clarification

-Danny

[900 byte] By [dan-ba] at [2007-10-2 22:21:05]
# 1

The spec says that

If X is a detached entity, the state of X is copies onto a pre-existing managed entity instance X' of the same identity or a new managed copy X' of X is created.

So the original instance X that was detatched remains unchanged by the call to em.merge(X). The managed instance X' that was updated by the call to em.merge(X) is the instance that was returned.

Managed instances may be a different class instance or may have had weaving or other symantics applied to them, which is why em.merge(X) may need to give you a different instance from the one you passed to it (i.e. this is a decision that allows implementers of EJB3 Persistence the flexibility to implement the functionality in different ways)

so yes, you need to do something like

entity = em.merge(entity);

in order for the instance variable entity to now point to the managed entity.

NB this should be highlighting the issue of what could happen if multiple instances in your VM reference entity... after doing entity = em.merge(entity) you may need to update all their references too or you could end up with a big mess

DrS@STVConsultantsa at 2007-7-14 1:38:19 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 2
Thank you. Unfortunately, no tutorial points these two things out. At least nonethat I found. Although I read the spec, it wasn't clear to me. So thanks formaking me understand :-)For the reference thing: I take care of that by using a cascading merge.
dan-ba at 2007-7-14 1:38:19 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 3

> For the reference thing: I take care of that by using

> a cascading merge.

Noooo, that's not what I'm getting at.... an example for you:

@Entity

public class Parent {

private List<Child> children;

...

}

@Entity

public class Child {

private Parent parent;

...

}

public class Client {

@PersistenceContext

EntityManager em;

...

void someMethod() {

...

Parent p;

p = em.find(Parent.class, mykey);

em.detatch(p);

...

Child c = p.getChildren().get(0);

...

p = em.merge(p);

...

assert c.getParent() != p;

...

}

}

The call to em.merge will merge all the children with your cascade... but any direct references that you have to the children will _still_ be the references to the detached entities.

DrS@STVConsultantsa at 2007-7-14 1:38:19 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 4

Uh! Okay...

I thought, that the container will take care of the references itself! I mean,

it follows the references to merge all the referenced entities so why not

also update the references itself?

Is there an effective way of updating all the references? I have 4 levels of

references here (like GreadGrandFather, GrandFather, Father, Son). The

client gives me the GreatGrandFather. Looks like a pretty expensive method

that I need (4 level loop?). Please say "Nooooo!" this time again :-)

I really appreciate your help! Thank you very much!

dan-ba at 2007-7-14 1:38:19 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 5

Well the solution is to re-navigate from the managed entity...

greatGrandFather = em.merge(greatGrandFather);

gives you a managed entity, as long as you only work starting from the managed entity, it will only give you references to managed objects...

the problem I was referring to is if you, somewhere else, have kept a reference to a Son instance, that reference does not link to the instance that greatGrandFather points to at all.

Hope this helps

DrS@STVConsultantsa at 2007-7-14 1:38:19 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...
# 6
I have written a blog post with diagrams that might help http://javaadventure.blogspot.com/2006/06/how-emmerge-actually-works.html
DrS@STVConsultantsa at 2007-7-14 1:38:19 > top of Java-index,Enterprise & Remote Computing,Enterprise Technologies...