views:

62

answers:

3

Hi everyone,

I have a one-to-many relationship between Part and Params (a "Part" has many "Params).

I'm trying to do something naive like this:

Part sourcePart = em.find(Part.class, partIdSource);
Part destPart = em.find(Part.class, partIdDest);

Collection<Param> paramListSource = sourcePart.getParamList();

destPart.setParamList(paramListSource);

Basically I want to copy all the parameters from sourcePart to destPart. Hopefully the persistence provider will automatically set the right foreign keys in the Param table/entity.

The above code will obviously not work.

Is there any easy way of doing this, or do I have to do create a new collection, then add each Param (creating new Param, setting attributes, etc) ?

Edit

I tried detaching the entity first like someone recommended in another thread but I get an exception (org.hibernate.PersistentObjectException: detached entity passed to persist: shared.entity.Param).

Part sourcePart = em.find(Part.class, partIdSource);
// force eager loading...
((List)sourcePart.getParamList()).get(0);

Part destPart = em.find(Part.class, partIdDest);

// detach entity
org.hibernate.Session session = ((org.hibernate.ejb.EntityManagerImpl) em.getDelegate()).getSession();
session.evict(sourcePart);

//causes exception "detached entity passed to persist"
destPart.setParamList(sourcePart.getParamList());
+1  A: 

Maybe you can implement a clone() method in Param. Then you could do paramListSource.clone().

Daniel Engmann
Clone kind of sucks because it returns Object. Use a cloning constructor instead: Param(Param toClone)Also, I don't see how you can guarantee that the particular implementation of the Collection has clone() implemented so that it does a deep copy.
Nick Orton
Hi Daniel, Nick. I'll eventually implement something like this. But I was hoping all these persistence layers are a bit more powerful and have features that can help in these kind of situations.
Bogdan
It doesn't have to return Object even if it inherits from Object you can actually do `public MyClass clone()` and it will work, and the compiler will realize you've overwritten the Object.clone() method. Also don't forget to call `(MyClass)super.clone()` to make sure that the object you get is actually an instance of the class you call it (if you extends MyClass and call it from there). And rememeber that super.clone() returns a shallow copy, so you need to do all the work of making them independent.
Andrei Fierbinteanu
+1  A: 

I'm pretty sure that what you're getting aren't actually Param instances, but proxy objects that implements Param's interface, so you may have to create new Param objects and copy the properties. Also, don't detach them from the session, since if they are proxies, they won't be able to fetch the other properties beside Id, which is the only thing populated initially (lazy fetching).

Andrei Fierbinteanu
is this valid even if I do smth like sourcePart.getParamList()).get(0) ?Shouldn't this force eager fetching?
Bogdan
I'm pretty sure that if you want a new object to be created you need to create a new Object, that way it's the actual class, not a proxy, and doesn't have anything extra like the id (which should get auto-filled), or any other filler properties already set on it, before trying to persist it.
Andrei Fierbinteanu
+2  A: 

Basically I want to copy all the parameters from sourcePart to destPart. Hopefully the persistence provider will automatically set the right foreign keys in the Param table/entity.

If you want to go the "evict way", making your entities Detached is NOT enough, you need to "nullify" the Id properties so that your entities become New again (persisting them must result in SQL INSERT). In pseudo code:

MyObject ob = session.get(idOfExisting);
hibernate.evict(ob);
ob.setId(null);
hibernate.save(ob);

But I find this dirty. I would iterate over the items of the list and use a copy constructor (without copying the Id properties) to create a new list and then set the copy on the destination object (and this would be provider agnostic).

Pascal Thivent
I eventually used the copy constructor. Although it seems I need to set in Param the destination Part instance too, otherwise it won't know what foreign key to set. I thought this would be done automatically...Thanks all for your advices!
Bogdan