-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 
Author Message
 Post subject: parent/child with assigned generators
PostPosted: Fri Aug 13, 2004 4:20 pm 
Newbie

Joined: Fri Aug 13, 2004 4:11 pm
Posts: 5
Location: Houston, TX
Hibernate version: 2.1

Mapping documents:
<hibernate-mapping>
<class name="Test" table="test">
<id name="id" column="id" type="string">
<generator class="assigned"/>
</id>

<property name="name" type="string"/>

<bag name="testChildren" table="test_children" cascade="all" inverse="true">
<key column="test_id"/>
<one-to-many class="TestChild"/>
</bag>
</class>

<class name="TestChild" table="test_children">
<id name="id" column="id" type="string" unsaved-value="null">
<generator class="assigned"/>
</id>

<many-to-one name="parent" column="test_id" not-null="true"/>

<property name="name" type="string"/>
</class>
</hibernate-mapping>

Code between sessionFactory.openSession() and session.close():
Transaction tx = session.beginTransaction();

Test test = new Test();
test.setId("DMH01");
test.setName("David");

//session.save(test);

java.util.List testChildren = new java.util.ArrayList();

TestChild testChild = new TestChild();
testChild.setId("child02");
testChild.setName("Britney");
testChild.setParent(test);
testChildren.add(testChild);

test.setTestChildren(testChildren);

//session.update(test);
session.save(test);
//session.save(testChild);


tx.commit();

Full stack trace of any exception that occurs:
Hibernate: insert into test (name, id) values (?, ?)
Hibernate: update test_children set test_id=?, name=? where id=?
Aug 13, 2004 3:15:36 PM net.sf.hibernate.impl.SessionImpl execute
SEVERE: Could not synchronize database state with session
net.sf.hibernate.HibernateException: SQL insert, update or delete failed (row not found)
at net.sf.hibernate.impl.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:25)
at net.sf.hibernate.persister.EntityPersister.update(EntityPersister.java:684)
at net.sf.hibernate.persister.EntityPersister.update(EntityPersister.java:642)
at net.sf.hibernate.impl.ScheduledUpdate.execute(ScheduledUpdate.java:52)
at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2418)
at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2372)
at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2240)
at net.sf.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:61)
at TestHibernate.main(TestHibernate.java:47)
Name and version of the database you are using:
MS SQL Server 2000

Debug level Hibernate log excerpt:


Trying to do parent/child with assigned generators. Tried uni-directional and bi-directional. Child rows are still called with update when they do not exist yet. Is there a way for this to work with assigned generators and have it cascade insert, update, delete?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 13, 2004 4:28 pm 
Expert
Expert

Joined: Thu Jan 29, 2004 2:31 am
Posts: 362
Location: Switzerland, Bern
read http://forum.hibernate.org/viewtopic.php?t=933496

HTH
Ernst


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 13, 2004 4:35 pm 
Newbie

Joined: Fri Aug 13, 2004 4:11 pm
Posts: 5
Location: Houston, TX
Yes, I read your suggestion there earlier. I tried putting a <version> and unsaved-value=null in, but it didn't seem to make a difference. Your post says cascade=all will not work with assigned identifiers, but is it supposed to work with one of your 4 suggestions (minus the generated identifier)?


Top
 Profile  
 
 Post subject:
PostPosted: Fri Aug 13, 2004 5:55 pm 
Newbie

Joined: Fri Aug 13, 2004 4:11 pm
Posts: 5
Location: Houston, TX
So I guess the crux of the problem is that cascade=all will end up being a saveOrUpdate. But the API docs says saveOrUpdate() will save by default:

Either save() or update() the given instance, depending upon the value of its identifier property. By default the instance is always saved. This behaviour may be adjusted by specifying an unsaved-value attribute of the identifier property mapping.

Seems like there is no way to know whether to save or update without querying the database to see if the object exists already.


Top
 Profile  
 
 Post subject:
PostPosted: Sat Aug 14, 2004 12:53 am 
Expert
Expert

Joined: Thu Jan 29, 2004 2:31 am
Posts: 362
Location: Switzerland, Bern
Quote:
I tried putting a <version> and unsaved-value=null in, but it didn't seem to make a difference.


All Options in the afore mentioned post do work. I've an old lagacy DB with all kinds of funny ID's, which I cannot change. On the other hand I'm a fan of persistency by reachability. This forces me to make use of all of this options.

May be you post again your code, mappings and so on to show how you added the version id in order I can have a look at it.

HTH
Ernst


Top
 Profile  
 
 Post subject:
PostPosted: Sun Aug 15, 2004 9:43 am 
Newbie

Joined: Fri Aug 13, 2004 4:11 pm
Posts: 5
Location: Houston, TX
Ernie, thanks for the help. I'm sure I didn't something stupid for the version not to work. But even if I get it to work, I cannot put the extra column and class field for the cascade to work. Is there any other way to do it with an assigned identifier that doesn't require version?

Thanks,
David


Top
 Profile  
 
 Post subject:
PostPosted: Mon Aug 16, 2004 3:51 am 
Expert
Expert

Joined: Thu Jan 29, 2004 2:31 am
Posts: 362
Location: Switzerland, Bern
This means option 4 is for you.

Make your own identifier Class and Interceptor. In my cas it's even a component.

My DAO has a createNewInstance Method witch does the id assignement. This way you don't have to worry about this in your business logic.

HTH
Ernst


The identifier class:
Quote:
package hello;

import java.io.Serializable;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;

public class CapiPK implements Serializable {

private Long mySystemId = null;
private Long myPid = null;
private boolean isUnsaved = true;


public CapiPK() {
super();
}
public CapiPK(Long systemId, Long pid) {
this();
mySystemId = systemId;
myPid = pid;
}
public CapiPK(long systemId, long pid) {
super();
mySystemId = new Long(systemId);
myPid = new Long(pid);
}
public Long getPid() {
return myPid;
}
public void setPid(Long pid) {
myPid = pid;
}
public Long getSystemId() {
return mySystemId;
}
public void setSystemId(Long systemId) {
mySystemId = systemId;
}

public boolean equals(Object obj) {
if (!(obj instanceof CapiPK)) return false;
CapiPK pk = (CapiPK)obj;
return new EqualsBuilder()
.append(mySystemId, pk.mySystemId)
.append(myPid, pk.myPid)
.isEquals();
}
public int hashCode() {
return new HashCodeBuilder()
.append(mySystemId)
.append(myPid)
.toHashCode();
}
public void setSaved() {
isUnsaved = false;
}
public Boolean isUnsaved() {
return isUnsaved ? Boolean.TRUE : Boolean.FALSE;
}
}



The Interceptor implementation:
Quote:
package hello;

import java.io.Serializable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Iterator;

import net.sf.hibernate.CallbackException;
import net.sf.hibernate.Interceptor;
import net.sf.hibernate.type.Type;

public class CapiInterceptor implements Interceptor {

public boolean onLoad(Object arg0, Serializable id, Object[] arg2,
String[] arg3, Type[] arg4) throws CallbackException {
if (id instanceof CapiPK) {
((CapiPK)id).setSaved();
}
return false;
}

public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState,
Object[] previousState, String[] propertyNames, Type[] arg5) throws CallbackException {
return false;
}

public boolean onSave(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) throws CallbackException {
if (id instanceof CapiPK) {
((CapiPK)id).setSaved();
}
return false;
}

public void onDelete(Object arg0, Serializable arg1, Object[] arg2,
String[] arg3, Type[] arg4) throws CallbackException {
}

public void preFlush(Iterator arg0) throws CallbackException {
return;
}

public void postFlush(Iterator arg0) throws CallbackException {
return;
}

public Boolean isUnsaved(Object object) {
try {
Method m = object.getClass().getMethod("getPk", null);
CapiPK pk = (CapiPK) m.invoke(object, null);
return pk.isUnsaved();
} catch (SecurityException e) {
throw new RuntimeException(this.getClass()+" cannot call Class.getMethod, due to missing permissions. " +
"Please make shure the appropriate permissions are granted.", e);
} catch (NoSuchMethodException e) {
// fine, let Hibernat do the rest
return null;
} catch (IllegalArgumentException e) {
// should never happen
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException("The getPk method of the class "+object.getClass()+" isn't public.");
} catch (InvocationTargetException e) {
// should never happen
throw new RuntimeException(e);
}
}

public int[] findDirty(Object arg0, Serializable arg1, Object[] arg2,
Object[] arg3, String[] arg4, Type[] arg5) {
return null;
}

public Object instantiate(Class arg0, Serializable arg1)
throws CallbackException {
return null;
}

}


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 7 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.