Need help with Hibernate? Read this first:
http://www.hibernate.org/ForumMailingli ... AskForHelp
Hibernate version:
3.0.5
Mapping documents:
Parent.hbm.xml
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>
<class
name="hib3jdk14Test.biDirOneToManyTest01.Parent"
table="parent"
lazy="true"
>
<id
name="parentId"
type="long"
column="parent_id"
>
<generator class="assigned"/>
</id>
<version
name="version"
type="integer"
column="version"
unsaved-value="negative"
/>
<property
name="parentName"
type="string"
column="parent_name"
length="50"
not-null="true"
>
</property>
<!-- Associations -->
<!-- bi-directional one-to-many association to Child01 -->
<set
name="children"
lazy="true"
inverse="true"
cascade="none"
>
<key>
<column name="parent_id" />
</key>
<one-to-many
class="hib3jdk14Test.biDirOneToManyTest01.Child01"
/>
</set>
</class>
</hibernate-mapping>
Child01.hbm.xml
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>
<class
name="hib3jdk14Test.biDirOneToManyTest01.Child01"
table="child01"
lazy="true"
>
<id
name="childId"
type="long"
column="child_id"
>
<generator class="assigned"/>
</id>
<version
name="version"
type="integer"
column="version"
unsaved-value="negative"
/>
<property
name="childName"
type="string"
column="child_name"
length="50"
not-null="true"
>
</property>
<!-- Associations -->
<!-- bi-directional many-to-one association to Parent -->
<many-to-one
name="parent"
class="hib3jdk14Test.biDirOneToManyTest01.Parent"
not-null="true"
>
<column name="parent_id" />
</many-to-one>
</class>
</hibernate-mapping>
POJOs:Parent.java:
Code:
package hib3jdk14Test.biDirOneToManyTest01;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
public class Parent implements Serializable {
/** identifier field */
private Long parentId;
private String parentName;
private int version = -1;
private Set children = new HashSet();
/** no-arg constructor for JavaBean tools */
public Parent() {
}
/** main constructor */
public Parent(Long parentId, String parentName) {
this.parentId = parentId;
this.parentName = parentName;
}
public Long getParentId() {
return this.parentId;
}
public void setParentId(Long parentId) {
this.parentId = parentId;
}
public String getParentName() {
return this.parentName;
}
public void setParentName(String parentName) {
this.parentName = parentName;
}
public int getVersion() {
return this.version;
}
public void setVersion(int version) {
this.version = version;
}
public Set getChildren() {
return this.children;
}
private void setChildren(Set children) {
this.children = children;
}
//scaffolding code for 1:n
public void addChild(Child01 child){
if (child == null){
throw new IllegalArgumentException("Can't add a null child");
}
child.setParent(this);
this.children.add(child);//in mapping inverse=true so should not trigger an update but it does..
//it also triggers a sql select of all the children
}
public String toString() {
return ("[parentId]" + getParentId() + "[parentName]" + getParentName());
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Parent)) return false;
final Parent parent = (Parent) o;
if (!getParentName().equals(parent.getParentName())) return false;
return true;
}
public int hashCode() {
int result;
result = getParentName().hashCode();
result = 29 * result;
return result;
}
}
Child01.java
Code:
package hib3jdk14Test.biDirOneToManyTest01;
import java.io.Serializable;
public class Child01 implements Serializable {
/** identifier field */
private Long childId;
private String childName;
private int version = -1;
private Parent parent;
/** no-arg constructor for JavaBean tools */
public Child01() {
}
/** main constructor
*/
public Child01(Long childId, String childName, Parent parent) {
this.childId = childId;
this.childName = childName;
parent.addChild(this);
}
public Long getChildId() {
return this.childId;
}
private void setChildId(Long childId) {
this.childId = childId;
}
public String getChildName() {
return this.childName;
}
public void setChildName(String childName) {
this.childName = childName;
}
public int getVersion() {
return this.version;
}
public void setVersion(int version) {
this.version = version;
}
public Parent getParent() {
return this.parent;
}
public void setParent(Parent parent) {
this.parent = parent;
}
public String toString() {
return ("[childId]" + getChildId() + "[childName]" + getChildName());
}
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Child01)) return false;
final Child01 child = (Child01) o;
if (!getChildName().equals(child.getChildName())) return false;
return true;
}
public int hashCode() {
int result;
result = getChildName().hashCode();
result = 29 * result;
return result;
}
}
Code between sessionFactory.openSession() and session.close():Code:
session = sf.openSession();
tx = session.beginTransaction();
System.out.println("**** Getting parent ****");
parent = (Parent)session.get(Parent.class, parentId);
System.out.println("**** Creating new Child ****");
Child01 child = new Child01(childId, childName, parent);
System.out.println("**** Saving Child ****");
session.save(child);
tx.commit();
session.close();
Full stack trace of any exception that occurs:
none
Name and version of the database you are using:
hsql
The generated SQL (show_sql=true):
[java] Hibernate: select parent0_.parent_id as parent1_0_, parent0_.version as version0_0_, parent0_.parent_name as parent3_0_0_ from parent parent0_ where parent0_.parent_id=?
[java] Hibernate: select children0_.parent_id as parent4_1_, children0_.child_id as child1_1_, children0_.child_id as child1_0_, children0_.version as version1_0_, children0_.child_name as child3_1_0_, children0_.parent_id as parent4_1_0_ from child01 children0_ where children0_.parent_id=?
[java] Hibernate: insert into child01 (version, child_name, parent_id, child_id) values (?, ?, ?, ?)
[java] Hibernate: update parent set version=?, parent_name=? where parent_id=? and version=?
Debug level Hibernate log excerpt:
[java] **** About to insert child ****
[java] 22:29:53,689 DEBUG SessionImpl: opened session at timestamp: 4614465919750144
[java] 22:29:53,690 DEBUG JDBCTransaction: begin
[java] 22:29:53,692 DEBUG ConnectionManager: opening JDBC connection
[java] 22:29:53,693 DEBUG DriverManagerConnectionProvider: total checked-out connections: 0
[java] 22:29:53,694 DEBUG DriverManagerConnectionProvider: using pooled JDBC connection, pool size: 0
[java] 22:29:53,696 DEBUG JDBCTransaction: current autocommit status: false
[java] **** Getting parent ****
[java] 22:29:53,702 DEBUG DefaultLoadEventListener: loading entity: [hib3jdk14Test.biDirOneToManyTest01.Parent#1]
[java] 22:29:53,704 DEBUG DefaultLoadEventListener: attempting to resolve: [hib3jdk14Test.biDirOneToManyTest01.Parent#1]
[java] 22:29:53,705 DEBUG DefaultLoadEventListener: object not resolved in any cache: [hib3jdk14Test.biDirOneToManyTest01.Parent#1]
[java] 22:29:53,727 DEBUG BasicEntityPersister: Materializing entity: [hib3jdk14Test.biDirOneToManyTest01.Parent#1]
[java] 22:29:53,728 DEBUG Loader: loading entity: [hib3jdk14Test.biDirOneToManyTest01.Parent#1]
[java] 22:29:53,734 DEBUG AbstractBatcher: about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
[java] 22:29:53,734 DEBUG SQL: select parent0_.parent_id as parent1_0_, parent0_.version as version0_0_, parent0_.parent_name as parent3_0_0_ from parent parent0_ where parent0_.parent_id=?
[java] Hibernate: select parent0_.parent_id as parent1_0_, parent0_.version as version0_0_, parent0_.parent_name as parent3_0_0_ from parent parent0_ where parent0_.parent_id=?
[java] 22:29:53,734 DEBUG AbstractBatcher: preparing statement
[java] 22:29:53,746 DEBUG LongType: binding '1' to parameter: 1
[java] 22:29:53,749 DEBUG AbstractBatcher: about to open ResultSet (open ResultSets: 0, globally: 0)
[java] 22:29:53,749 DEBUG Loader: processing result set
[java] 22:29:53,749 DEBUG Loader: result set row: 0
[java] 22:29:53,749 DEBUG Loader: result row: EntityKey[hib3jdk14Test.biDirOneToManyTest01.Parent#1]
[java] 22:29:53,750 DEBUG Loader: Initializing object from ResultSet: [hib3jdk14Test.biDirOneToManyTest01.Parent#1]
[java] 22:29:53,754 DEBUG BasicEntityPersister: Hydrating entity: [hib3jdk14Test.biDirOneToManyTest01.Parent#1]
[java] 22:29:53,754 DEBUG IntegerType: returning '0' as column: version0_0_
[java] 22:29:53,754 DEBUG StringType: returning 'Parent 1' as column: parent3_0_0_
[java] 22:29:53,754 DEBUG TwoPhaseLoad: Version: 0
[java] 22:29:53,755 DEBUG Loader: done processing result set (1 rows)
[java] 22:29:53,755 DEBUG AbstractBatcher: about to close ResultSet (open ResultSets: 1, globally: 1)
[java] 22:29:53,755 DEBUG AbstractBatcher: about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
[java] 22:29:53,755 DEBUG AbstractBatcher: closing statement
[java] 22:29:53,757 DEBUG Loader: total objects hydrated: 1
[java] 22:29:53,758 DEBUG TwoPhaseLoad: resolving associations for [hib3jdk14Test.biDirOneToManyTest01.Parent#1]
[java] 22:29:53,763 DEBUG CollectionLoadContext: creating collection wrapper:[hib3jdk14Test.biDirOneToManyTest01.Parent.children#1]
[java] 22:29:53,764 DEBUG TwoPhaseLoad: done materializing entity [hib3jdk14Test.biDirOneToManyTest01.Parent#1]
[java] 22:29:53,764 DEBUG PersistenceContext: initializing non-lazy collections
[java] 22:29:53,764 DEBUG Loader: done entity load
[java] **** Creating new Child ****
[java] 22:29:53,765 DEBUG DefaultInitializeCollectionEventListener: initializing collection [hib3jdk14Test.biDirOneToManyTest01.Parent.children#1]
[java] 22:29:53,766 DEBUG DefaultInitializeCollectionEventListener: checking second-level cache
[java] 22:29:53,766 DEBUG DefaultInitializeCollectionEventListener: collection not cached
[java] 22:29:53,766 DEBUG Loader: loading collection: [hib3jdk14Test.biDirOneToManyTest01.Parent.children#1]
[java] 22:29:53,766 DEBUG AbstractBatcher: about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
[java] 22:29:53,766 DEBUG SQL: select children0_.parent_id as parent4_1_, children0_.child_id as child1_1_, children0_.child_id as child1_0_, children0_.version as version1_0_, children0_.child_name as child3_1_0_, children0_.parent_id as parent4_1_0_ from child01 children0_ where children0_.parent_id=?
[java] Hibernate: select children0_.parent_id as parent4_1_, children0_.child_id as child1_1_, children0_.child_id as child1_0_, children0_.version as version1_0_, children0_.child_name as child3_1_0_, children0_.parent_id as parent4_1_0_ from child01 children0_ where children0_.parent_id=?
[java] 22:29:53,766 DEBUG AbstractBatcher: preparing statement
[java] 22:29:53,767 DEBUG LongType: binding '1' to parameter: 1
[java] 22:29:53,767 DEBUG AbstractBatcher: about to open ResultSet (open ResultSets: 0, globally: 0)
[java] 22:29:53,769 DEBUG Loader: result set contains (possibly empty) collection: [hib3jdk14Test.biDirOneToManyTest01.Parent.children#1]
[java] 22:29:53,769 DEBUG CollectionLoadContext: uninitialized collection: initializing
[java] 22:29:53,770 DEBUG Loader: processing result set
[java] 22:29:53,770 DEBUG Loader: done processing result set (0 rows)
[java] 22:29:53,770 DEBUG AbstractBatcher: about to close ResultSet (open ResultSets: 1, globally: 1)
[java] 22:29:53,770 DEBUG AbstractBatcher: about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
[java] 22:29:53,821 DEBUG AbstractBatcher: closing statement
[java] 22:29:53,822 DEBUG Loader: total objects hydrated: 0
[java] 22:29:53,824 DEBUG CollectionLoadContext: 1 collections were found in result set for role: hib3jdk14Test.biDirOneToManyTest01.Parent.children
[java] 22:29:53,825 DEBUG CollectionLoadContext: collection fully initialized: [hib3jdk14Test.biDirOneToManyTest01.Parent.children#1]
[java] 22:29:53,827 DEBUG CollectionLoadContext: 1 collections initialized for role: hib3jdk14Test.biDirOneToManyTest01.Parent.children
[java] 22:29:53,828 DEBUG PersistenceContext: initializing non-lazy collections
[java] 22:29:53,830 DEBUG Loader: done loading collection
[java] 22:29:53,831 DEBUG DefaultInitializeCollectionEventListener: collection initialized
[java] **** Saving Child ****
[java] 22:29:53,834 DEBUG DefaultSaveOrUpdateEventListener: saving transient instance
[java] 22:29:53,835 DEBUG AbstractSaveEventListener: generated identifier: 1, using strategy: org.hibernate.id.Assigned
[java] 22:29:53,836 DEBUG AbstractSaveEventListener: saving [hib3jdk14Test.biDirOneToManyTest01.Child01#1]
[java] 22:29:53,838 DEBUG Versioning: Seeding: 0
[java] 22:29:53,840 DEBUG JDBCTransaction: commit
[java] 22:29:53,841 DEBUG SessionImpl: automatically flushing session
[java] 22:29:53,842 DEBUG AbstractFlushingEventListener: flushing session
[java] 22:29:53,844 DEBUG AbstractFlushingEventListener: processing flush-time cascades
[java] 22:29:53,845 DEBUG AbstractFlushingEventListener: dirty checking collections
[java] 22:29:53,870 DEBUG CollectionEntry: Collection dirty: [hib3jdk14Test.biDirOneToManyTest01.Parent.children#1]
[java] 22:29:53,872 DEBUG AbstractFlushingEventListener: Flushing entities and processing referenced collections
[java] 22:29:53,874 DEBUG DefaultFlushEntityEventListener: Updating entity: [hib3jdk14Test.biDirOneToManyTest01.Parent#1]
[java] 22:29:53,875 DEBUG Versioning: Incrementing: 0 to 1
[java] 22:29:53,880 DEBUG Collections: Collection found: [hib3jdk14Test.biDirOneToManyTest01.Parent.children#1], was: [hib3jdk14Test.biDirOneToManyTest01.Parent.children#1] (initialized)
[java] 22:29:53,881 DEBUG AbstractFlushingEventListener: Processing unreferenced collections
[java] 22:29:53,883 DEBUG AbstractFlushingEventListener: Scheduling collection removes/(re)creates/updates
[java] 22:29:53,886 DEBUG AbstractFlushingEventListener: Flushed: 1 insertions, 1 updates, 0 deletions to 2 objects
[java] 22:29:53,887 DEBUG AbstractFlushingEventListener: Flushed: 0 (re)creations, 1 updates, 0 removals to 1 collections
[java] 22:29:53,889 DEBUG Printer: listing entities:
[java] 22:29:53,890 DEBUG Printer: hib3jdk14Test.biDirOneToManyTest01.Child01{childName=child01 1, childId=1, parent=hib3jdk14Test.biDirOneToManyTest01.Parent#1, version=0}
[java] 22:29:53,893 DEBUG Printer: hib3jdk14Test.biDirOneToManyTest01.Parent{parentId=1, parentName=Parent 1, children=[hib3jdk14Test.biDirOneToManyTest01.Child01#1], version=0}
[java] 22:29:53,895 DEBUG AbstractFlushingEventListener: executing flush
[java] 22:29:53,896 DEBUG BasicEntityPersister: Inserting entity: [hib3jdk14Test.biDirOneToManyTest01.Child01#1]
[java] 22:29:53,897 DEBUG BasicEntityPersister: Version: 0
[java] 22:29:53,899 DEBUG AbstractBatcher: about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
[java] 22:29:53,900 DEBUG SQL: insert into child01 (version, child_name, parent_id, child_id) values (?, ?, ?, ?)
[java] Hibernate: insert into child01 (version, child_name, parent_id, child_id) values (?, ?, ?, ?)
[java] 22:29:53,903 DEBUG AbstractBatcher: preparing statement
[java] 22:29:53,904 DEBUG BasicEntityPersister: Dehydrating entity: [hib3jdk14Test.biDirOneToManyTest01.Child01#1]
[java] 22:29:53,906 DEBUG IntegerType: binding '0' to parameter: 1
[java] 22:29:53,907 DEBUG StringType: binding 'child01 1' to parameter: 2
[java] 22:29:53,911 DEBUG LongType: binding '1' to parameter: 3
[java] 22:29:53,912 DEBUG LongType: binding '1' to parameter: 4
[java] 22:29:53,914 DEBUG AbstractBatcher: Adding to batch
[java] 22:29:53,915 DEBUG AbstractBatcher: Executing batch size: 1
[java] 22:29:53,917 DEBUG AbstractBatcher: about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
[java] 22:29:53,918 DEBUG AbstractBatcher: closing statement
[java] 22:29:53,924 DEBUG ConnectionManager: running Session.finalize()
[java] 22:29:53,948 DEBUG BasicEntityPersister: Updating entity: [hib3jdk14Test.biDirOneToManyTest01.Parent#1]
[java] 22:29:53,950 DEBUG BasicEntityPersister: Existing version: 0 -> New version: 1
[java] 22:29:53,951 DEBUG AbstractBatcher: about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
[java] 22:29:53,952 DEBUG SQL: update parent set version=?, parent_name=? where parent_id=? and version=?
[java] Hibernate: update parent set version=?, parent_name=? where parent_id=? and version=?
[java] 22:29:53,955 DEBUG AbstractBatcher: preparing statement
[java] 22:29:53,957 DEBUG BasicEntityPersister: Dehydrating entity: [hib3jdk14Test.biDirOneToManyTest01.Parent#1]
[java] 22:29:53,958 DEBUG IntegerType: binding '1' to parameter: 1
[java] 22:29:53,960 DEBUG StringType: binding 'Parent 1' to parameter: 2
[java] 22:29:53,961 DEBUG LongType: binding '1' to parameter: 3
[java] 22:29:53,963 DEBUG IntegerType: binding '0' to parameter: 4
[java] 22:29:53,965 DEBUG AbstractBatcher: about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
[java] 22:29:53,967 DEBUG AbstractBatcher: closing statement
[java] 22:29:53,980 DEBUG AbstractFlushingEventListener: post flush
[java] 22:29:53,982 DEBUG JDBCContext: before transaction completion
[java] 22:29:53,983 DEBUG SessionImpl: before transaction completion
[java] 22:29:53,985 DEBUG JDBCTransaction: committed JDBC Connection
[java] 22:29:53,986 DEBUG JDBCContext: after transaction completion
[java] 22:29:53,987 DEBUG SessionImpl: after transaction completion
[java] 22:29:53,989 DEBUG SessionImpl: closing session
[java] 22:29:53,990 DEBUG ConnectionManager: closing JDBC connection [ (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
[java] 22:29:53,991 DEBUG DriverManagerConnectionProvider: returning connection to pool, pool size: 1
[java] 22:29:53,993 DEBUG JDBCContext: after transaction completion
[java] 22:29:53,994 DEBUG SessionImpl: after transaction completion
[java] **** After inserting child ****
As shown above I have set up a bidirectional one to many association between a Parent and Child01. In the Parent I have an addChild method which adds the Child01 to the collection of children in the Parent and sets the Parent in the Child01 soas to maintain the bidirectional association. When I create a Child01 I use the addChild method in the Parent - but this is triggering a select of all children for this Parent and an update of the Parent in addition to the desired insert of the Child01.
Have I done something incorrect in the mapping/code to cause this? How can I prevent this from happening? In my real application the end user may not have update permission on the Parent which will cause the transaction to fail. Also there may be many thousands of children for a given Parent so the select would kill performance.
Thanks for any advice.
Grainne.