Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA lazy fetch not working and throwing LazyInitializationException

i am a new bee to spring data JPA, so i was trying to make something out of it, so that i can know about fetching Modes, but it's throwing a exception, Please make a look at the code.

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

  String name;

  @OneToMany(mappedBy = "state", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
  Set<Constituency> constituencies ;

  public void fetchLazyCollection() {
    getConstituencies().size();
  }
}

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

  String name;

  @ManyToOne
  @JoinColumn(name = "state_id")
  State state;
}

So, as you can see there are two classes State and Constituency and from State to Constituency one-to-many mapping exists and vice versa there is many-to-one. Please let me know if i have made any stupid mistake here.

@Test
public void delhiShouldHaveTwoConstituency(){
  State delhi = new State();
  delhi.setName("New Delhi");

  Constituency northWest = new Constituency();
  northWest.setName("North West");
  northWest.setState(delhi);

  Constituency southDelhi = new Constituency();
  southDelhi.setName("South Delhi");
  southDelhi.setState(delhi);

  Set<Constituency> constituencies = new HashSet<Constituency>();
  constituencies.add(northWest);
  constituencies.add(southDelhi);

  delhi.setConstituencies(constituencies);

  stateRepository.save(delhi);

  List<State> states= stateRepository.findByName("New Delhi");
  states.get(0).fetchLazyCollection();
  assertThat(delhi.getConstituencies().size(), is(2));
}

Now, i have a test which is saving a state with two of its constituencies and then i am trying to retrieve them again using :

List<State> states= stateRepository.findByName("New Delhi");

According to my understanding, i am assuming as this statement will execute, constituencies in State won't get initialize until next statement executes which is to invoke fetchLazyCollection but as fetchLazyCollection invokes it's throwing exception of

could not initialize Proxy - No Session

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.prateekj.model.State.constituencies, could not initialize proxy - no Session
at org.hibernate.collection.internal.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:567)
at org.hibernate.collection.internal.AbstractPersistentCollection.withTemporarySessionIfNeeded(AbstractPersistentCollection.java:187)
at org.hibernate.collection.internal.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:138)
at org.hibernate.collection.internal.PersistentSet.size(PersistentSet.java:156)
at com.prateekj.model.State.fetchLazyCollection(State.java:35)
at com.prateekj.repositories.StateRepositoryTest.shouldDoIt(StateRepositoryTest.java:53)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:83)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.junit.runner.JUnitCore.run(JUnitCore.java:160)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:65)

as i am assuming, each unit tests in java maintain its own session of interaction with database, may be i am wrong, can anyone please tell me what wrong i have done here ? Any help will be appreciated.

like image 487
Prateek Jain Avatar asked May 29 '14 00:05

Prateek Jain


People also ask

How do you fix org hibernate LazyInitializationException could not initialize proxy no session?

if you are using annotation configuration: add @Proxy(lazy=false) to all your entity classes. That's all about how to fix Exception in thread "main" org. hibernate. LazyInitializationException: could not initialize proxy - no Session.

How will load a lazily loaded items in hibernate to avoid lazy load exception?

Just make the lazy=false and hibernate will load the child when parent is loaded from the database. In the above configuration. If lazy="false" : - when you load the Employee object that time child object Address is also loaded and set to setAddresss() method. If you call employee.

How lazy loading works in JPA?

By default, JPA uses the lazy fetch strategy in associations of type @ElementCollection. Thus, any access to the collection in a closed Persistence Context will result in an exception. This test throws an exception when we try to access the phone list because the Persistence Context is closed.


2 Answers

You get the LazyInitializationException because after you get out of the stateRepository.findByName("New Delhi"), the Hibernate Session gets closed, and you are not able to fetch additional associations outside of a running Hibernate Session.

Adding @Transactional to your test will fix this issue and you won't have to call:

states.get(0).fetchLazyCollection();

It's best to fetch the lazy associations you need in the original entity query:

select s 
from State s 
left join fetch s.constituencies 
where s.name = :stateName
like image 173
Vlad Mihalcea Avatar answered Nov 03 '22 00:11

Vlad Mihalcea


set lazy flag true to your collection mapping as following

@OneToMany(mappedBy = "objectId", cascade = CascadeType.ALL, orphanRemoval = true , fetch = FetchType.EAGER)
like image 31
Pravin Bansal Avatar answered Nov 02 '22 23:11

Pravin Bansal