I'm trying to create a simple Parent/Child relationship with the JPA 2  API and Hibernate 3.6.7 or 4.0.0.CR4 as a provider, and I discovered some strange behaviors which can be reproduced on a simple setup.
In a nutshell I have two entities: Parent and Child both using embeded keys ParentKey and ChildKey. The definitions follow:
Code:
@Embeddable
public class ChildKey
    implements Serializable {
    
    @Column(nullable = false)
    private String  name;
    
    @Column(nullable = false)
    private Integer number;
}
Code:
@Embeddable
public class ParentKey
    implements Serializable {
    
    @Column(nullable = false, updatable = false)
    private String name;
}
Code:
@Entity
public class Child {
    @EmbeddedId
    private ChildKey key;
    
    @Column
    private String   value;
}
Code:
@Entity
public class Parent {
    @EmbeddedId
    private ParentKey   key;
    
    @Column
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    private List<Child> children;
    public void setChildren(List<Child> children) {
        this.children = children;
    }
}
The test consist in a first transaction creating a parent, add a couple of children, persist it in the database and a second retrieve it, remove one child while adding another one and merge it to the database:
Code:
@Transactional
public void populate() {
    for (int i = 0; i < 2; i++) {
        final Parent parent = new Parent("Parent-" + i);
        List<Child> children = new ArrayList<Child>();
        for (int j = 0; j < 2; j++) {
            children.add(new Child(parent.getName(), j));
        }
        parent.setChildren(children);
        em.persist(parent);
    }
}
    
@Transactional
public void removeChild() {
    final Parent parent = em.find(Parent.class, new ParentKey("Parent-0"));
    List<Child> children = new ArrayList<Child>(parent.getChildren());
    children.remove(0);
    children.add(new Child(parent.getName(), 42));
    parent.setChildren(children);
    em.merge(parent);
}
As is, this does not work as I expect since it creates a relationship table. So I added a @JoinColumn to the children attribute in the Parent class.
Code:
    @Column
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumn(name="name")
    private List<Child> children;
When running my test I notice that Hibernate seems to find out what should be done: creation of a new child and removal of another one. However it fails at runtime with the following exception:
Code:
[main] DEBUG org.hibernate.SQL  - update Child set name=null where name=?
Hibernate: update Child set name=null where name=?
[main] DEBUG o.h.p.c.AbstractCollectionPersister  - done deleting collection
[main] DEBUG org.hibernate.jdbc.AbstractBatcher  - Executing batch size: 1
[main] DEBUG org.hibernate.jdbc.AbstractBatcher  - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
[main] DEBUG o.h.util.JDBCExceptionReporter  - Could not execute JDBC batch update [update Child set name=null where name=?]
org.h2.jdbc.JdbcBatchUpdateException: NULL not allowed for column "NAME"; SQL statement:
update Child set name=null where name=? [23502-160]
   at org.h2.jdbc.JdbcPreparedStatement.executeBatch(JdbcPreparedStatement.java:1107) ~[h2-1.3.160.jar:1.3.160]
Which is expected as the name column is part of the Child's key and can, therefore not be null.
I did explore another path which consist in replacing the collection contents rather than the collection itself:
Code:
    @Column
    @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
    @JoinColumn(name="name")
    private List<Child> children = new ArrayList<Child>();
    public void setChildren(List<Child> children) {
        this.children.clear();
        this.children.addAll(children);
    }
It also fails with the following exception:
Code:
[main] DEBUG org.hibernate.SQL  - update Child set name=null where name=? and number=?
Hibernate: update Child set name=null where name=? and number=?
[main] DEBUG org.hibernate.jdbc.AbstractBatcher  - about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
[main] DEBUG o.h.util.JDBCExceptionReporter  - could not delete collection rows: [entity.Parent.children#component[name]{name=Parent-0}] [update Child set name=null where name=? and number=?]
org.h2.jdbc.JdbcSQLException: Invalid value "3" for parameter "parameterIndex" [90008-160]
   at org.h2.message.DbException.getJdbcSQLException(DbException.java:329) ~[h2-1.3.160.jar:1.3.160]
   at org.h2.message.DbException.get(DbException.java:169) ~[h2-1.3.160.jar:1.3.160]
   at org.h2.message.DbException.getInvalidValueException(DbException.java:215) ~[h2-1.3.160.jar:1.3.160]
   at org.h2.jdbc.JdbcPreparedStatement.setParameter(JdbcPreparedStatement.java:1270) ~[h2-1.3.160.jar:1.3.160]
   at org.h2.jdbc.JdbcPreparedStatement.setInt(JdbcPreparedStatement.java:308) ~[h2-1.3.160.jar:1.3.160]
   at org.hibernate.type.descriptor.sql.IntegerTypeDescriptor$1.doBind(IntegerTypeDescriptor.java:52) ~[hibernate-core-3.6.7.Final.jar:3.6.7.Final]
   at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:91) ~[hibernate-core-3.6.7.Final.jar:3.6.7.Final]
   at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:283) ~[hibernate-core-3.6.7.Final.jar:3.6.7.Final]
   at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:278) ~[hibernate-core-3.6.7.Final.jar:3.6.7.Final]
   at org.hibernate.type.ComponentType.nullSafeSet(ComponentType.java:340) ~[hibernate-core-3.6.7.Final.jar:3.6.7.Final]
   at org.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:121) ~[hibernate-core-3.6.7.Final.jar:3.6.7.Final]
   at org.hibernate.persister.collection.AbstractCollectionPersister.writeElementToWhere(AbstractCollectionPersister.java:844) ~[hibernate-core-3.6.7.Final.jar:3.6.7.Final]
   at org.hibernate.persister.collection.AbstractCollectionPersister.deleteRows(AbstractCollectionPersister.java:1316) ~[hibernate-core-3.6.7.Final.jar:3.6.7.Final]
   at org.hibernate.action.CollectionUpdateAction.execute(CollectionUpdateAction.java:84) [hibernate-core-3.6.7.Final.jar:3.6.7.Final]
   at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:273) [hibernate-core-3.6.7.Final.jar:3.6.7.Final]
   at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:265) [hibernate-core-3.6.7.Final.jar:3.6.7.Final]
   at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:187) [hibernate-core-3.6.7.Final.jar:3.6.7.Final]
   at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321) [hibernate-core-3.6.7.Final.jar:3.6.7.Final]
   at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51) [hibernate-core-3.6.7.Final.jar:3.6.7.Final]
   at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1216) [hibernate-core-3.6.7.Final.jar:3.6.7.Final]
   at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:383) [hibernate-core-3.6.7.Final.jar:3.6.7.Final]
   at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:133) [hibernate-core-3.6.7.Final.jar:3.6.7.Final]
   at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:76) [hibernate-entitymanager-3.6.7.Final.jar:3.6.7.Final]
This is even stranger as Hibernate still tries to nullify the name column and, additionally, tries to set the third parameter of a 2 parameter query.