-->
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.  [ 3 posts ] 
Author Message
 Post subject: How to define object/collection initialization order?
PostPosted: Mon Sep 19, 2005 12:40 pm 
Newbie

Joined: Thu Aug 25, 2005 10:04 am
Posts: 6
Hi,

I have a strange initialization problem which I could pin down to the way how hibernate initializes objects and collections.

Imagine the following simple classes:

Code:
class Parent {
  Long id;
  String name;
  HashSet childs;
}


and
Code:
class Child {
  Long id;
  String name;
  Parent parent;
}


(Bean Methods left out)

The business keys (as suggested on http://www.hibernate.org/109.html) for Parent is "name" and for Child is "name" and "parent". Hashcode() and equals() are implemented correctly respecting the business keys.

When I retrieve objects from the database by childDAO.getById(id) I can debug the following sequence:

- child gets created
- parent gets created
- parents collection is initialized with a HashSet containing the child
- childs.setParent(parent) is invoked.

In the third step an incorrectly initialized child gets inserted into the HashSet (without the business key "parent" set) resulting in an invalid key. The child itself gets its parent correctly set in step four, but the key of the HashSet Entry is never found again.

How can I handle these problems? My first thought was to change the order of step three and four, but since this is hibernates job, I ask my question here. Any solution?

bye,

Stefan

Hibernate version:
3.0

Mapping documents:
too simple

Code between sessionFactory.openSession() and session.close():
childDAO.getById(id)

Full stack trace of any exception that occurs:
no exception

Name and version of the database you are using:
mysql 4.1

Debug level Hibernate log excerpt:
Debug with org.hibernate.event=DEBUG
The first entry to the set is by hibernates setChilds() call.
The second entry to the set is invoked by child.setParent() which adds itself to the parent collection.

Code:
11005 [main] DEBUG def.DefaultLoadEventListener  - loading entity: [Child#4]
11006 [main] DEBUG def.DefaultLoadEventListener  - attempting to resolve: [Child#4]
11006 [main] DEBUG def.DefaultLoadEventListener  - object not resolved in any cache: [Child#4]
11047 [main] DEBUG def.DefaultLoadEventListener  - loading entity: [Parent#3]
11050 [main] DEBUG def.DefaultLoadEventListener  - creating new proxy for entity
11051 [main] DEBUG def.DefaultLoadEventListener  - attempting to resolve: [Parent#3]
11051 [main] DEBUG def.DefaultLoadEventListener  - object not resolved in any cache: [Parent#3]
11056 [main] DEBUG def.DefaultLoadEventListener  - creating new proxy for entity
11063 [main] DEBUG def.DefaultInitializeCollectionEventListener  - initializing collection [Parent.childs#3]
11063 [main] DEBUG def.DefaultInitializeCollectionEventListener  - checking second-level cache
11063 [main] DEBUG def.DefaultInitializeCollectionEventListener  - collection not cached
11076 [main] DEBUG def.DefaultLoadEventListener  - loading entity: [Child#4]
11077 [main] DEBUG def.DefaultLoadEventListener  - entity found in session cache
11079 [main] DEBUG def.DefaultLoadEventListener  - attempting to resolve: [Child#4]
11079 [main] DEBUG def.DefaultLoadEventListener  - resolved object in session cache: [Child#4]
11080 [main] DEBUG def.DefaultInitializeCollectionEventListener  - collection initialized
11080 [main] INFO Parent  - hashcode of child = -536855941
11141 [main] INFO Parent  - content of child = Child@17644c8[name=child,parent=<null>,id=4]
11141 [main] INFO Parent  - collection size = 1
11151 [main] DEBUG def.DefaultLoadEventListener  - loading entity: [Parent#3]
11151 [main] DEBUG def.DefaultLoadEventListener  - entity found in session cache
11151 [main] DEBUG def.DefaultLoadEventListener  - attempting to resolve: [Parent#3]
11151 [main] DEBUG def.DefaultLoadEventListener  - resolved object in session cache: [Parent#3]
11152 [main] DEBUG def.DefaultInitializeCollectionEventListener  - collection initialized
11161 [main] INFO Parent  - hashcode of child = -968294839
11141 [main] INFO Parent  - content of child = Child@17644c8[name=child,parent=Parent@17644c8[name=parent, id=3],id=4]
11161 [main] INFO Parent  - collection size = 2


Top
 Profile  
 
 Post subject:
PostPosted: Mon Sep 19, 2005 2:19 pm 
Pro
Pro

Joined: Fri Sep 02, 2005 4:21 am
Posts: 206
Location: Vienna
Hi,

Could you post your mapping, your configuration and the SQL statement Hibernate generates. It tried to reproduce the behavior you describe - without "success".

Erik


Top
 Profile  
 
 Post subject:
PostPosted: Tue Sep 20, 2005 4:24 am 
Newbie

Joined: Thu Aug 25, 2005 10:04 am
Posts: 6
Hi,

I have extracted the classes from a bigger project and isolated the problem (which is still the same as in my first posting). It should be reproducable. The only external dependencies are ToStringBuilder, HashCodeBuilder, EqualsBuilder and Log, which are all from the jakarta commons project.

Parent:
Code:
public class Parent extends BaseEntity {
    transient private Log log = LogFactory.getLog(Parent.class);

    private String name;

    private Set<Child> childs = new HashSet<Child>();

    Parent() {
        super();
    }

    public Parent(String name) {
        super();
        setName(name);
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Set<Child> getChilds() {
        return childs;
    }

    private void setChilds(Set<Child> childs) {
        for (Child child : childs) {
            log.info("setter: hashcode = " + child.hashCode());
            log.info("setter: object = " + child);
        }
        log.info("setter: size " + childs.size());
        this.childs = childs;
    }

    public void addChild(Child child) {
        log.info("adder: hashcode = " + child.hashCode());
        log.info("adder: object = " + child);
        childs.add(child);
        log.info("adder: size " + childs.size());
    }

    public void removeChild(Child child) {
        childs.remove(child);
    }

    public int hashCode() {
        return new HashCodeBuilder(-665290105, 1060143345).append(this.name).toHashCode();
    }

    public boolean equals(Object object) {
        if (object == this) {
            return true;
        }
        if (!(object instanceof Parent)) {
            return false;
        }
        Parent rhs = (Parent) object;
        return new EqualsBuilder().append(this.name, rhs.getName()).isEquals();
    }
}

Child:
Code:
public class Child extends BaseEntity {
    transient private Log log = LogFactory.getLog(Child.class);

    private String name;
    private Parent parent;

    Child() {
        super();
    }

    public Child(String name, Parent parent) {
        super();
        setName(name);
        setParent(parent);
    }

    public Parent getParent() {
        return parent;
    }

    private void setParent(Parent parent) {
        if (!(parent == null ? this.parent == null : parent.equals(this.parent)))  {
            if (this.parent != null) {
                this.parent.removeChild(this);
            }
            this.parent = parent;
            if (parent != null) {
                parent.addChild(this);
            }  else {
                log.warn("trying to set a business key to null, this will fail!");
            }
        }
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int hashCode() {
        return new HashCodeBuilder(1765049893, 159477687).append(this.name).append(this.parent).toHashCode();
    }

    public boolean equals(Object object) {
        if (object == this) {
            return true;
        }
        if (!(object instanceof Child)) {
            return false;
        }
        Child rhs = (Child) object;
        return new EqualsBuilder().append(this.name, rhs.getName()).append(this.parent, rhs.getParent()).isEquals();
    }
}


BaseEntity:
Code:
public abstract class BaseEntity implements Serializable {

    private Long id;
    private Integer version;

    public Long getId() {
        return id;
    }

    protected void setId(Long id) {
        this.id = id;
    }

    protected Integer getVersion() {
        return version;
    }

    protected void setVersion(Integer version) {
        this.version = version;
    }

    public String toString() {
        return ToStringBuilder.reflectionToString(this, ToStringStyle.DEFAULT_STYLE, false);
    }
}

Parent hbm.xml
Code:
<hibernate-mapping>
  <class name="test.Parent">
    <id name="id" column="id">
      <generator class="increment"/>
    </id>
    <version name="version" column="version" type="java.lang.Integer" />
    <property name="name" />
    <set name="childs" inverse="true" cascade="all,delete-orphan">
      <key column="parent" not-null="true" update="true" />
      <one-to-many class="test.Child" />
    </set>
  </class>
</hibernate-mapping>

Child hbm.xml
Code:
<hibernate-mapping>
  <class name="test.Child">
    <id name="id" column="id">
      <generator class="increment" />
    </id>
    <version name="version" column="version" type="java.lang.Integer" />
    <property name="name" />
    <many-to-one name="parent" class="test.Parent" not-null="true" insert="true" update="true" />
  </class>   
</hibernate-mapping>

Logging output:
Code:
6820 [main] INFO dao.BaseDAOTestCase  - retrieve
6836 [main] INFO datasource.JdbcTransactionObjectSupport  - JDBC 3.0 Savepoint class is available
6868 [main] DEBUG def.DefaultLoadEventListener  - loading entity: [test.Child#1]
6869 [main] DEBUG def.DefaultLoadEventListener  - attempting to resolve: [test.Child#1]
6869 [main] DEBUG def.DefaultLoadEventListener  - object not resolved in any cache: [test.Child#1]
6921 [main] DEBUG def.DefaultLoadEventListener  - loading entity: [test.Parent#1]
6921 [main] DEBUG def.DefaultLoadEventListener  - creating new proxy for entity
6923 [main] DEBUG def.DefaultLoadEventListener  - attempting to resolve: [test.Parent#1]
6923 [main] DEBUG def.DefaultLoadEventListener  - object not resolved in any cache: [test.Parent#1]
6947 [main] DEBUG def.DefaultInitializeCollectionEventListener  - initializing collection [test.Parent.childs#1]
6947 [main] DEBUG def.DefaultInitializeCollectionEventListener  - checking second-level cache
6947 [main] DEBUG def.DefaultInitializeCollectionEventListener  - collection not cached
6950 [main] DEBUG def.DefaultLoadEventListener  - loading entity: [test.Child#1]
6951 [main] DEBUG def.DefaultLoadEventListener  - entity found in session cache
6951 [main] DEBUG def.DefaultLoadEventListener  - attempting to resolve: [test.Child#1]
6951 [main] DEBUG def.DefaultLoadEventListener  - resolved object in session cache: [test.Child#1]
6955 [main] DEBUG def.DefaultInitializeCollectionEventListener  - collection initialized
6956 [main] INFO test.Parent  - setter: hashcode = -2100885451
6979 [main] INFO test.Parent  - setter: object = test.Child@24de7d[name=<null>,parent=<null>,id=1,version=0]
6979 [main] INFO test.Parent  - setter: size 1
6981 [main] INFO test.Parent  - adder: hashcode = 1649469942
6984 [main] INFO test.Parent  - adder: object = test.Child@24de7d[name=<null>,parent=test.Parent@1bdb58[name=parent,childs=[test.Child@24de7d[test.Child@24de7dtest.Child@24de7dtest.Child@24de7d]],id=1,version=0],id=1,version=0]
6984 [main] INFO test.Parent  - adder: size 2
6984 [main] DEBUG def.AbstractFlushingEventListener  - flushing session
6985 [main] DEBUG def.AbstractFlushingEventListener  - processing flush-time cascades
6986 [main] DEBUG def.AbstractSaveEventListener  - persistent instance of: test.Child
6986 [main] DEBUG def.DefaultSaveOrUpdateEventListener  - ignoring persistent instance
6986 [main] DEBUG def.DefaultSaveOrUpdateEventListener  - object already associated with session: [test.Child#1]
6986 [main] DEBUG def.AbstractSaveEventListener  - persistent instance of: test.Child
6986 [main] DEBUG def.DefaultSaveOrUpdateEventListener  - ignoring persistent instance
6986 [main] DEBUG def.DefaultSaveOrUpdateEventListener  - object already associated with session: [test.Child#1]
6988 [main] DEBUG def.AbstractFlushingEventListener  - dirty checking collections
6989 [main] DEBUG def.AbstractFlushingEventListener  - Flushing entities and processing referenced collections
7007 [main] DEBUG def.DefaultFlushEntityEventListener  - Updating entity: [test.Parent#1]
7016 [main] DEBUG def.AbstractFlushingEventListener  - Processing unreferenced collections
7017 [main] DEBUG def.AbstractFlushingEventListener  - Scheduling collection removes/(re)creates/updates
7020 [main] DEBUG def.AbstractFlushingEventListener  - Flushed: 0 insertions, 1 updates, 0 deletions to 2 objects
7020 [main] DEBUG def.AbstractFlushingEventListener  - Flushed: 0 (re)creations, 1 updates, 0 removals to 1 collections
7021 [main] DEBUG def.AbstractFlushingEventListener  - executing flush
7026 [main] DEBUG def.AbstractFlushingEventListener  - post flush

Mysql query log:
Code:
050920 10:22:45      42 Query       SET autocommit=0
                     42 Prepare     [1] select child0_.id as id0_, child0_.version as version10_0_, child0_.parent as parent10_0_, child0_.name as name10_0_ from Child child0_ where child0_.id=?
                     42 Execute     [1] select child0_.id as id0_, child0_.version as version10_0_, child0_.parent as parent10_0_, child0_.name as name10_0_ from Child child0_ where child0_.id=1
                     42 Prepare     [2] select parent0_.id as id0_, parent0_.version as version4_0_, parent0_.name as name4_0_ from Parent parent0_ where parent0_.id=?
                     42 Execute     [2] select parent0_.id as id0_, parent0_.version as version4_0_, parent0_.name as name4_0_ from Parent parent0_ where parent0_.id=1
                     42 Prepare     [3] select childs0_.parent as parent__, childs0_.id as id__, childs0_.id as id0_, childs0_.version as version10_0_, childs0_.parent as parent10_0_, childs0_.name as name10_0_ from Child childs0_ where childs0_.parent=?
                     42 Execute     [3] select childs0_.parent as parent__, childs0_.id as id__, childs0_.id as id0_, childs0_.version as version10_0_, childs0_.parent as parent10_0_, childs0_.name as name10_0_ from Child childs0_ where childs0_.parent=1
                     42 Prepare     [4] update Parent set version=?, name=? where id=? and version=?
                     42 Execute     [4] update Parent set version=2, name='parent' where id=1 and version=1
                     42 Query       commit


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 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.