Hi,
I think I found a bug in the idbag. It occurs when you insert a new element and delete an old one just after in the same session.
In the 2.1.8 version, the code of the beforeRemove method is
Code:
private void beforeRemove(int index) {
Object removedId = identifiers.get( new Integer(index) );
int last = values.size()-1;
for ( int i=index; i<last; i++ ) {
identifiers.put( new Integer(i), identifiers.get( new Integer(i+1) ) );
}
identifiers.put( new Integer(last), removedId );
}
With this code, you put a new 'null' identifier in the identifiers map for the object to be inserted. Thus, during the insertion procedure, in the preInsert method, no identifier is generated.
I think the code of the beforeRemove method should look like
Code:
private void beforeRemove(int index) {
Object removedId = identifiers.get( new Integer(index) );
int last = values.size()-1;
for ( int i=index; i<last; i++ ) {
if (identifiers.contains(new Integer(i))
identifiers.put( new Integer(i), identifiers.get( new Integer(i+1) ) );
}
identifiers.put( new Integer(last), removedId );
}
Here is all the details on my test that reproduce the problem with hibernate 3.0b4
Hibernate version: 3.0b4
Mapping documents:Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 2.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="test.TestObject">
<id name="id" type="integer">
<generator class="increment"/>
</id>
<property name="name"/>
<idbag name="myBag">
<collection-id type="integer" column="bag_id">
<generator class="increment"/>
</collection-id>
<key>
<column name="test_id"/>
</key>
<element type="string" column="bag_name"/>
</idbag>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():Code:
SessionFactory sessionFactory = new Configuration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
TestObject test = new TestObject();
test.setName("test");
test.getMyBag().add("item1");
session.save(test);
tx.commit();
session.close();
session = sessionFactory.openSession();
tx = session.beginTransaction();
test = (TestObject) session.get(TestObject.class, new Integer(1));
test.getMyBag().add("item2");
test.getMyBag().remove("item1");
tx.commit();
session.close();
Full stack trace of any exception that occurs:Code:
org.hibernate.exception.GenericJDBCException: could not insert collection rows: [test.TestObject.myBag#1]
at org.hibernate.exception.ErrorCodeConverter.handledNonSpecificException(ErrorCodeConverter.java:92)
at org.hibernate.exception.ErrorCodeConverter.convert(ErrorCodeConverter.java:80)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43)
at org.hibernate.collection.AbstractCollectionPersister.insertRows(AbstractCollectionPersister.java:1011)
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.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:271)
at org.hibernate.event.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:24)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:719)
at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:84)
at TestHibernate.main(TestHibernate.java:47)
Caused by: java.sql.SQLException: Try to insert null into a non-nullable column: column: BAG_ID table: MYBAG in statement [insert into myBag (test_id, bag_id, bag_name) values (?, ?, ?)]
at org.hsqldb.jdbc.jdbcUtil.throwError(Unknown Source)
at org.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate(Unknown Source)
at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:23)
at org.hibernate.collection.AbstractCollectionPersister.insertRows(AbstractCollectionPersister.java:997)
... 9 more
Name and version of the database you are using:
Occurs with hsqldb and firebird
The generated SQL (show_sql=true):
2005-03-09 09:53:52,281 : insert into TestObject (name, id) values (?, ?)
2005-03-09 09:53:52,281 : insert into myBag (test_id, bag_id, bag_name) values (?, ?, ?)
2005-03-09 09:53:52,312 : select testobject0_.id as id0_, testobject0_.name as name0_0_ from TestObject testobject0_ where testobject0_.id=?
2005-03-09 09:53:52,328 : select mybag0_.test_id as test1___, mybag0_.bag_name as bag2___, mybag0_.bag_id as bag3___ from myBag mybag0_ where mybag0_.test_id=?
2005-03-09 09:53:52,328 : delete from myBag where bag_id=?
2005-03-09 09:53:52,328 : insert into myBag (test_id, bag_id, bag_name) values (?, ?, ?)
2005-03-09 09:53:52,328 : SQL Error: -10, SQLState: 23000