My object has a list of primitive values (say, strings), where values could possibly be null.
I'm getting a constraint violation when trying to change previously saved null to non-null.
I've implemented the simplest possible test case that reproduces the problem.
Test scenario is:
Session 1
1. Set a.b[0] to null
2. Save or update.
Session 2
3. Set a.b[0] to "b".
4. Save or update.
5. Enjoy an exception.
I've traced a bit and it seems that in PersistentList.needsUpdating(...) you only update if old value was not null:
Code:
return i<sn.size() && sn.get(i)!=null && list.get(i)!=null && elemType.isDirty( list.get(i), sn.get(i), getSession() );
Since I previously had null, the item is not updated but inserted instead. And I get the constraint violation.
Is this a bug? Not critical, but quite annoying.
Hibernate version: Hibernate 3.0.5 Mapping documents:Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping
package="net.orless.hibernate.tests">
<class name="A" table="A">
<id name="id"/>
<list name="b">
<key column="id"/>
<list-index column="index"/>
<element column="value" type="string" not-null="false"/>
</list>
</class>
</hibernate-mapping>
Unit test:Code:
public class A {
private String id;
private List b = new ArrayList();
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List getB() {
return b;
}
public void setB(List b) {
this.b = b;
}
}
public class ATest extends TestCase {
public ATest(String x) {
super(x);
}
public void testSaveOrUpdate() throws HibernateException, SQLException {
final A a = new A();
a.setId("a");
a.getB().add(null);
Session s = openSession();
Transaction t = s.beginTransaction();
s.saveOrUpdate(a);
t.commit();
s.close();
a.getB().set(0, "b");
s = openSession();
t = s.beginTransaction();
s.saveOrUpdate(a);
t.commit();
s.close();
}
protected String[] getMappings() {
return new String[]{ "A.hbm.xml" };
}
}
Full stack trace of any exception that occurs:
org.hibernate.exception.ConstraintViolationException: could not insert collection rows: [net.orless.hibernate.tests.A.b#a]
at org.hibernate.exception.ErrorCodeConverter.convert(ErrorCodeConverter.java:74)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.persister.collection.AbstractCollectionPersister.insertRows(AbstractCollectionPersister.java:1087)
at org.hibernate.action.CollectionUpdateAction.execute(CollectionUpdateAction.java:48)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:239)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:223)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:139)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:274)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:730)
at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:324)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:86)
at net.orless.hibernate.tests.ATest.testSaveOrUpdate(ATest.java:32)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at junit.framework.TestCase.runTest(TestCase.java:154)
at net.orless.hibernate.tests.TestCase.runTest(TestCase.java:129)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:474)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:342)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:194)
Caused by: java.sql.SQLException: Unique constraint violation: in statement [insert into b (id, index, value) values (?, ?, ?)]
at org.hsqldb.jdbc.jdbcUtil.throwError(jdbcUtil.java:62)
at org.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate(jdbcPreparedStatement.java:412)
at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:22)
at org.hibernate.persister.collection.AbstractCollectionPersister.insertRows(AbstractCollectionPersister.java:1073)
... 26 more
Name and version of the database you are using:
HSQL 1.7.3