My problem is that I have a many-to-one association that is has a multi-column foreign key that is mapped to a component in the joining class. This association always seems to be eagerly loaded in a seperate select. It is killing the performance of some of the common reports that need to be generated, as a query returning a hundreds of these objects requires hundreds more queries to uneccassarily load the association.
If I have another many-to-one association to Bar (lazyBar in my example), but use a single column joining to the primary key, it shows that it can be proxied/lazy loaded.
The association Foo.bar is mapped with update=false and insert=false, I just want it there for easy traversal of the object graph. (in my real object model, the columns equivalent to uk1 and uk2 are owned/updated by other many-to-one associations)
If you would like a zip of an basic eclipse project with this code, then email me at dcampagnoli ~at~ nd.edu.au
Hibernate version:
3.0.5
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.Foo"
table="FOO"
dynamic-update="false"
dynamic-insert="false"
lazy="true"
>
<id
name="id"
column="id"
type="java.lang.Long"
>
<generator class="increment">
</generator>
</id>
<many-to-one
name="bar"
class="test.Bar"
cascade="none"
fetch="select"
update="false"
insert="false"
access="property"
property-ref="uk"
>
<column name="fk1" />
<column name="fk2" />
</many-to-one>
<many-to-one
name="lazyBar"
class="test.Bar"
cascade="none"
fetch="select"
update="true"
insert="true"
access="property"
>
<column name="lazyBar" />
</many-to-one>
<property
name="fk1"
type="java.lang.Long"
update="true"
insert="true"
access="property"
column="fk1"
/>
<property
name="fk2"
type="java.lang.Long"
update="true"
insert="true"
access="property"
column="fk2"
/>
</class>
</hibernate-mapping>
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.Bar"
table="BAR"
dynamic-update="false"
dynamic-insert="false"
lazy="true"
>
<id
name="id"
column="id"
type="java.lang.Long"
>
<generator class="increment">
</generator>
</id>
<component
name="uk"
class="test.UK"
access="property"
insert="false"
update="false"
unique="true"
>
<property
name="uk1"
type="java.lang.Long"
update="false"
insert="false"
access="property"
column="uk1"
/>
<property
name="uk2"
type="java.lang.Long"
update="false"
insert="false"
access="property"
column="uk2"
/>
</component>
<property
name="uk1"
type="java.lang.Long"
update="true"
insert="true"
access="property"
column="uk1"
/>
<property
name="uk2"
type="java.lang.Long"
update="true"
insert="true"
access="property"
column="uk2"
/>
</class>
</hibernate-mapping>
Code between sessionFactory.openSession() and session.close():Code:
// save two bars. the first will be used for the component mapped association
Bar bar = new Bar();
bar.setUk1(new Long(1));
bar.setUk2(new Long(2));
session.save(bar);
Bar lazyBar = new Bar();
lazyBar.setUk1(new Long(3));
lazyBar.setUk2(new Long(4));
session.save(lazyBar);
// save two foo's. The uk's (1, 2) match that of bar
session.save(new Foo(1, 2, bar, lazyBar));
session.save(new Foo(1, 2, bar, lazyBar));
session.flush();
session.close();
System.out.println();
session = factory.openSession();
System.out.println("Quering...");
List foos = session.createQuery("from Foo f").list();
System.out.println("Found " + foos.size());
Foo foo = (Foo) foos.iterator().next();
System.out.println("retrieving bar");
System.out.println(foo.getBar());
System.out.println("retrieving lazyBar");
System.out.println(foo.getLazyBar());
Full stack trace of any exception that occurs:
N/A
Name and version of the database you are using:
Problem found with SQL Server. Test case done with HSQL
The generated SQL (show_sql=true): (includes my System.out calls)
Hibernate: insert into BAR (uk1, uk2, id) values (?, ?, ?)
Hibernate: insert into BAR (uk1, uk2, id) values (?, ?, ?)
Hibernate: insert into FOO (lazyBar, fk1, fk2, id) values (?, ?, ?, ?)
Hibernate: insert into FOO (lazyBar, fk1, fk2, id) values (?, ?, ?, ?)
Quering...
Hibernate: select foo0_.id as id, foo0_.fk1 as fk2_0_, foo0_.fk2 as fk3_0_, foo0_.lazyBar as lazyBar0_ from FOO foo0_
Hibernate: select bar0_.id as id0_, bar0_.uk1 as uk2_1_0_, bar0_.uk2 as uk3_1_0_ from BAR bar0_ where bar0_.uk1=? and bar0_.uk2=?
Hibernate: select bar0_.id as id0_, bar0_.uk1 as uk2_1_0_, bar0_.uk2 as uk3_1_0_ from BAR bar0_ where bar0_.uk1=? and bar0_.uk2=?
Found 2
retrieving bar
test.Bar@16be68f
retrieving lazyBar
Hibernate: select bar0_.id as id0_, bar0_.uk1 as uk2_1_0_, bar0_.uk2 as uk3_1_0_ from BAR bar0_ where bar0_.id=?
test.Bar@126f827
Debug level Hibernate log excerpt:
09:16:04,375 DEBUG [SQL] select foo0_.id as id, foo0_.fk1 as fk2_0_, foo0_.fk2 as fk3_0_, foo0_.lazyBar as lazyBar0_ from FOO foo0_
Hibernate: select foo0_.id as id, foo0_.fk1 as fk2_0_, foo0_.fk2 as fk3_0_, foo0_.lazyBar as lazyBar0_ from FOO foo0_
09:16:04,375 DEBUG [AbstractBatcher] preparing statement
09:16:04,375 DEBUG [AbstractBatcher] about to open ResultSet (open ResultSets: 0, globally: 0)
09:16:04,375 DEBUG [Loader] processing result set
09:16:04,375 DEBUG [Loader] result set row: 0
09:16:04,375 DEBUG [LongType] returning '1' as column: id
09:16:04,375 DEBUG [Loader] result row: EntityKey[test.Foo#1]
09:16:04,375 DEBUG [Loader] Initializing object from ResultSet: [test.Foo#1]
09:16:04,375 DEBUG [BasicEntityPersister] Hydrating entity: [test.Foo#1]
09:16:04,375 DEBUG [LongType] returning '1' as column: fk2_0_
09:16:04,375 DEBUG [LongType] returning '2' as column: fk3_0_
09:16:04,375 DEBUG [LongType] returning '2' as column: lazyBar0_
09:16:04,375 DEBUG [LongType] returning '1' as column: fk2_0_
09:16:04,375 DEBUG [LongType] returning '2' as column: fk3_0_
09:16:04,375 DEBUG [Loader] result set row: 1
09:16:04,375 DEBUG [LongType] returning '2' as column: id
09:16:04,375 DEBUG [Loader] result row: EntityKey[test.Foo#2]
09:16:04,375 DEBUG [Loader] Initializing object from ResultSet: [test.Foo#2]
09:16:04,375 DEBUG [BasicEntityPersister] Hydrating entity: [test.Foo#2]
09:16:04,375 DEBUG [LongType] returning '1' as column: fk2_0_
09:16:04,375 DEBUG [LongType] returning '2' as column: fk3_0_
09:16:04,375 DEBUG [LongType] returning '2' as column: lazyBar0_
09:16:04,375 DEBUG [LongType] returning '1' as column: fk2_0_
09:16:04,375 DEBUG [LongType] returning '2' as column: fk3_0_
09:16:04,375 DEBUG [Loader] done processing result set (2 rows)
09:16:04,375 DEBUG [AbstractBatcher] about to close ResultSet (open ResultSets: 1, globally: 1)
09:16:04,375 DEBUG [AbstractBatcher] about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
09:16:04,375 DEBUG [AbstractBatcher] closing statement
09:16:04,375 DEBUG [Loader] total objects hydrated: 2
09:16:04,375 DEBUG [TwoPhaseLoad] resolving associations for [test.Foo#1]
09:16:04,390 DEBUG [Loader] loading entity: [test.Bar#component[uk1,uk2]{uk2=2, uk1=1}]
09:16:04,390 DEBUG [AbstractBatcher] about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
09:16:04,390 DEBUG [SQL] select bar0_.id as id0_, bar0_.uk1 as uk2_1_0_, bar0_.uk2 as uk3_1_0_ from BAR bar0_ where bar0_.uk1=? and bar0_.uk2=?
Hibernate: select bar0_.id as id0_, bar0_.uk1 as uk2_1_0_, bar0_.uk2 as uk3_1_0_ from BAR bar0_ where bar0_.uk1=? and bar0_.uk2=?
09:16:04,390 DEBUG [AbstractBatcher] preparing statement
09:16:04,390 DEBUG [LongType] binding '1' to parameter: 1
09:16:04,390 DEBUG [LongType] binding '2' to parameter: 2
09:16:04,390 DEBUG [AbstractBatcher] about to open ResultSet (open ResultSets: 0, globally: 0)
09:16:04,390 DEBUG [Loader] processing result set
09:16:04,390 DEBUG [Loader] result set row: 0
09:16:04,390 DEBUG [LongType] returning '1' as column: id0_
09:16:04,390 DEBUG [Loader] result row: EntityKey[test.Bar#1]
09:16:04,390 DEBUG [Loader] Initializing object from ResultSet: [test.Bar#1]
09:16:04,390 DEBUG [BasicEntityPersister] Hydrating entity: [test.Bar#1]
09:16:04,390 DEBUG [LongType] returning '1' as column: uk2_1_0_
09:16:04,390 DEBUG [LongType] returning '2' as column: uk3_1_0_
09:16:04,390 DEBUG [LongType] returning '1' as column: uk2_1_0_
09:16:04,390 DEBUG [LongType] returning '2' as column: uk3_1_0_
09:16:04,390 DEBUG [Loader] done processing result set (1 rows)
09:16:04,390 DEBUG [AbstractBatcher] about to close ResultSet (open ResultSets: 1, globally: 1)
09:16:04,390 DEBUG [AbstractBatcher] about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
09:16:04,390 DEBUG [AbstractBatcher] closing statement
09:16:04,390 DEBUG [Loader] total objects hydrated: 1
09:16:04,390 DEBUG [TwoPhaseLoad] resolving associations for [test.Bar#1]
09:16:04,390 DEBUG [TwoPhaseLoad] done materializing entity [test.Bar#1]
09:16:04,390 DEBUG [Loader] done entity load
09:16:04,390 DEBUG [DefaultLoadEventListener] loading entity: [test.Bar#2]
09:16:04,390 DEBUG [DefaultLoadEventListener] creating new proxy for entity
09:16:04,390 DEBUG [TwoPhaseLoad] done materializing entity [test.Foo#1]
09:16:04,390 DEBUG [TwoPhaseLoad] resolving associations for [test.Foo#2]
09:16:04,390 DEBUG [Loader] loading entity: [test.Bar#component[uk1,uk2]{uk2=2, uk1=1}]
09:16:04,390 DEBUG [AbstractBatcher] about to open PreparedStatement (open PreparedStatements: 0, globally: 0)
09:16:04,390 DEBUG [SQL] select bar0_.id as id0_, bar0_.uk1 as uk2_1_0_, bar0_.uk2 as uk3_1_0_ from BAR bar0_ where bar0_.uk1=? and bar0_.uk2=?
Hibernate: select bar0_.id as id0_, bar0_.uk1 as uk2_1_0_, bar0_.uk2 as uk3_1_0_ from BAR bar0_ where bar0_.uk1=? and bar0_.uk2=?
09:16:04,390 DEBUG [AbstractBatcher] preparing statement
09:16:04,390 DEBUG [LongType] binding '1' to parameter: 1
09:16:04,390 DEBUG [LongType] binding '2' to parameter: 2
09:16:04,390 DEBUG [AbstractBatcher] about to open ResultSet (open ResultSets: 0, globally: 0)
09:16:04,390 DEBUG [Loader] processing result set
09:16:04,390 DEBUG [Loader] result set row: 0
09:16:04,390 DEBUG [LongType] returning '1' as column: id0_
09:16:04,406 DEBUG [Loader] result row: EntityKey[test.Bar#1]
09:16:04,406 DEBUG [Loader] done processing result set (1 rows)
09:16:04,406 DEBUG [AbstractBatcher] about to close ResultSet (open ResultSets: 1, globally: 1)
09:16:04,406 DEBUG [AbstractBatcher] about to close PreparedStatement (open PreparedStatements: 1, globally: 1)
09:16:04,406 DEBUG [AbstractBatcher] closing statement
09:16:04,406 DEBUG [Loader] total objects hydrated: 0
09:16:04,406 DEBUG [Loader] done entity load
09:16:04,406 DEBUG [DefaultLoadEventListener] loading entity: [test.Bar#2]
09:16:04,406 DEBUG [DefaultLoadEventListener] entity proxy found in session cache
09:16:04,406 DEBUG [TwoPhaseLoad] done materializing entity [test.Foo#2]
09:16:04,406 DEBUG [PersistenceContext] initializing non-lazy collections
09:16:04,406 DEBUG [JDBCContext] after autocommit
Found 2