tags:

views:

582

answers:

3

I have a parent class with the following field with cascading option:

public class Parent {
  @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL)
  @Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)
  private final Set<Child> children = new HashSet<Child>();
  public addChild(Child child) { children.add(child); }
}

In my application I want to add a child and then call JPA merge on the parent class, automatically persisting my new child. This all works, however, the origional child reference I inserted into my parent object has changed, meaning I cannot retrieve the ID of my persisted child. Is there any way I can tell hibernate to re-use my old child reference instead of making a new one? during the merge

A: 

Just get the merged instance of your parent:

parent = entityManager.merge(parent);

Update:

What you want is not possible. Either manually merge() the child, and then add it to the parent, or get the new child instance from the parent collection and use it instead.

Bozho
I know, but then I only get the merged instance of my parent. I want the merged instance of my child to retrieve its ID. Ofcourse I can retrieve the last element from my children set, but thats incredibly nasty.
Jeroen
it should have them as well, as part of the new parent.
Bozho
I want to do the following:Child child = new Child();parent.addChild(child);service.saveParent(parent);// do things with persisted child reference e.g. child.getId();
Jeroen
not possible. see my update.
Bozho
Why is this not possible? Why does hibernate make a copy of my child object and persist that instead.. are you sure this isn't just some kind of option I can switch off?
Jeroen
no. merge() creates a new object by spec, if the current is not associated with the session.
Bozho
A: 

For many actions, Hibernate generates an event that can be listened for and some support code for listening.

If you're using Spring in conjunction with Hibernate, for instance, you can register a class org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener as a listener for hibernate's merge event (from I think spring-orm.jar) by putting the following in your hibernate.cfg.xml (or whatever file is referenced in your spring setup for hibernate config):

    <event type="merge">
        <listener class="org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener"/>
    </event>

or by adding an map in your sessionFactory bean:

    <bean id="sessionFactory" 
          class="org.springframework.orm.hibernate3.LocalSessionFactoryBean"
          p:dataSource-ref="dataSource">
    <property name="configLocation" value="WEB-INF/classes/hibernate.cfg.xml"/>
    <property name="eventListeners">
            <map>
                    <entry key="merge">
                            <bean class="org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener"/>
                    </entry>
            </map>
    </property>

If you do either of these, this listener should set the id in the original object. If you're not using Spring, there's likely a way to get a listener connected that's similar to one of these.

I haven't tested the child behavior you're looking for, but I'm pretty sure that a merge on the parent will trigger a merge on the child so that the listener will be called for both.

The setup for JPA might be different, but I suspect it's possible, and hope this gives clues.

Don Roby
I was able to add the listener to my persistence.xml<property name="hibernate.ejb.event.merge" value="org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener" />However now I get an OptimisticLockException when saving an object with cascading elements
Jeroen
OptimisticLockException was thrown because I declared a @Version attribute on each of my domain models. I eventually solved this problem by extending the IdTransferringMergeEventListener and copying my version value from the result into the origional.Much thanks for pointing me in the right direction!!
Jeroen
Glad it helped, and I hope it doesn't cause issues elsewhere. I have not used this in a JPA context, and don't know the full impact.
Don Roby
A: 

Hi Jeroen

Could you post your extension to IdTransferringMergeEventListener?

I am trying to do the same but cannot get hold of the new version number.

Christian