• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Hibernate One-To-Many bidirectional

 
ayan sevi
Greenhorn
Posts: 21
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 17278
6
IntelliJ IDE Mac Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
 
ayan sevi
Greenhorn
Posts: 21
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
Posts: 17278
6
IntelliJ IDE Mac Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
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
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic