IntelliJ Java IDE
The moose likes Object Relational Mapping and the fly likes Hibernate One-To-Many bidirectional Big Moose Saloon
  Search | Java FAQ | Recent Topics
Register / Login
JavaRanch » Java Forums » Java » Object Relational Mapping
Reply Bookmark "Hibernate One-To-Many bidirectional" Watch "Hibernate One-To-Many bidirectional" New topic
Author

Hibernate One-To-Many bidirectional

ayan sevi
Greenhorn

Joined: Sep 21, 2006
Posts: 21
Hi,

Got a problem with hibernate lazy loading for one to many bidirectional relationship. Let's say I have the following class:

@Entity
public class User {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;

@OneToMany(cascade={CascadeType.ALL}, fetch=FetchType.LAZY, mappedBy="user")
private List<Account> accounts;

....
}

@Entity
public class Account {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Integer id;

@ManyToOne
private User user;

....
}

and with the use of the following test case:

....
public void testCascadeUserAccount() {
// get User
User user = dao.get(1);
assertNotNull(user);
assertTrue(user.getId() == 1);

// add new account
Account account = newAccount();
account.setUser(user);
user.getAccounts().add(account); // OOPS! error was thrown here!!
dao.save(user);

assertTrue(user.getAccounts().size() == 3);

// check the list
List<Account> accounts = user.getAccounts();
assertNotNull(accounts);
for (Accounts a : accounts) {
log.debug("Account................" + a.toString());
assertTrue(a.getId() > 0);
}
}
....

An exception was thrown...

[emessaging] 2007-04-25 19:37:13 ERROR [main] LazyInitializationException.<init>(19) | failed to lazily initialize a collection of role: com.sample.model.User.accounts, no session or session was closed
org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.sample.model.User.accounts, no session or session was closed
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)
at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)
at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:97)
at org.hibernate.collection.PersistentBag.size(PersistentBag.java:225)
at com.g1.emessaging.dao.AccountDaoTest.testCascadeUserAccount(GatewayDaoTest.java:149)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at junit.framework.TestCase.runTest(TestCase.java:164)
at junit.framework.TestCase.runBare(TestCase.java:130)
at org.springframework.test.ConditionalTestCase.runBare(ConditionalTestCase.java:69)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:120)
at junit.framework.TestSuite.runTest(TestSuite.java:230)
at junit.framework.TestSuite.run(TestSuite.java:225)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.apache.maven.surefire.junit.JUnitTestSet.execute(JUnitTestSet.java:213)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:138)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:125)
at org.apache.maven.surefire.Surefire.run(Surefire.java:132)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:290)
at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:818)


but when I changed my test case into this, such that I queried again the user object to the database, and from there, assert that getAccounts().size() is equal to three, it runs fine.


....
public void testCascadeUserAccount() {
// get User
User user = dao.get(1);
assertNotNull(user);
assertTrue(user.getId() == 1);

// add new account
Account account = newAccount();
account.setUser(user);
//user.getAccounts().add(account); // OOPS! error was thrown here!!
dao.save(user);

//assertTrue(user.getAccounts().size() == 3); // this will also cause error when not commented

// code changes, to get again the modified user from the db
User modifiedUser = dao.get(1);
assertNotNull(modifiedUser);
assertEquals(modifiedUser.getAccounts().size() == 3);

// check the list
List<Account> accounts = user.getAccounts();
assertNotNull(accounts);
for (Accounts a : accounts) {
log.debug("Account................" + a.toString());
assertTrue(a.getId() > 0);
}
}
....



Does anyone has a clear explanation to this??

Thanks for your help....
Mark Spritzler
ranger
Sheriff

Joined: Feb 05, 2001
Posts: 16622

Yes, basically you can get the size, because there are Proxy objects in the Collection, that only have the ids of the many records. It has no data.

If you try to add an object to the collection, or read an object from the collection, Hibernate will want to go to the database to load the data, because it was lazy loaded. But since you are no longer in a Unit of Work, you have no Sesson available, and therefore it cannot access the database anymore and throws a LazyInitializationException.

Mark


Perfect World Programming, LLC - Two Laptop Bag - Tube Organizer
How to Ask Questions the Smart Way FAQ
ayan sevi
Greenhorn

Joined: Sep 21, 2006
Posts: 21
Great... , didn't know it works like that.

But when should we say in Hibernate, that your still on the same Unit of Work, or now your on a different one?

Is unit of work same as transaction?

Cheers
Mark Spritzler
ranger
Sheriff

Joined: Feb 05, 2001
Posts: 16622

Originally posted by ayan sevi:
Great... , didn't know it works like that.

But when should we say in Hibernate, that your still on the same Unit of Work, or now your on a different one?

Is unit of work same as transaction?

Cheers


you can associate unit of work=transaction. better to associate Unit of Work=Session.

Mark
 
 
subject: Hibernate One-To-Many bidirectional
 
Threads others viewed
Ejb3unit: Could not instantiate dialect class
MockStrutsTestCase configuration problem.
java null pointer exception when calling create on a localhome
Transaction timeout settings - OpenEJB
Anyone know how to construct a one to many mapping with Hibernate / Java?
WebSphere development made easy
without the weight of IBM tools
http://www.myeclipseide.com

cast iron skillet 49er

more from paul wheaton's glorious empire of web junk: cast iron skillet diatomaceous earth rocket mass heater sepp holzer raised garden beds raising chickens lawn care CFL flea control missoula heat permaculture