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.  [ 1 post ] 
Author Message
 Post subject: Strange behaviors in @OneToMany relationship.
PostPosted: Mon Oct 17, 2011 8:20 am 
Newbie

Joined: Mon Oct 17, 2011 5:34 am
Posts: 1
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.


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

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.