JSF Hibernate no session or session was closed

  • Themenstarter Themenstarter Gast2
  • Beginndatum Beginndatum
G

Gast2

Gast
Hallo zusammen,

ich bekomme immer eine hibernate error, den ich mir nicht erklären kann:
Code:
Caused by: org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: test.A, no session or session was closed
	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:383) [:3.6.0.Final]
	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:375) [:3.6.0.Final]
	at org.hibernate.collection.AbstractPersistentCollection.initialize(AbstractPersistentCollection.java:368) [:3.6.0.Final]
	at org.hibernate.collection.AbstractPersistentCollection.write(AbstractPersistentCollection.java:208) [:3.6.0.Final]
	at org.hibernate.collection.PersistentBag.add(PersistentBag.java:297) [:3.6.0.Final]
	at faces.beans.controller.StatusBeanController.findSendung(StatusBeanController.java:83) [:]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [:1.6.0_24]
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) [:1.6.0_24]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) [:1.6.0_24]
	at java.lang.reflect.Method.invoke(Method.java:597) [:1.6.0_24]
	at org.apache.el.parser.AstValue.invoke(AstValue.java:196) [:6.0.0.Final]
	at org.apache.el.MethodExpressionImpl.invoke(MethodExpressionImpl.java:276) [:6.0.0.Final]
	at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:43) [:6.0.0.Final]
	at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:56) [:6.0.0.Final]
	at org.jboss.weld.util.el.ForwardingMethodExpression.invoke(ForwardingMethodExpression.java:43) [:6.0.0.Final]
	at org.jboss.weld.el.WeldMethodExpression.invoke(WeldMethodExpression.java:56) [:6.0.0.Final]
	at com.sun.faces.facelets.el.TagMethodExpression.invoke(TagMethodExpression.java:102) [:2.0.3-]
	at javax.faces.component.MethodBindingMethodExpressionAdapter.invoke(MethodBindingMethodExpressionAdapter.java:84) [:2.0.3-]
	... 30 more

Beispiel:
Java:
@Entity
public class A{
	@Id
	@GeneratedValue
	private Long id;
@OneToMany(cascade = CascadeType.ALL)
private List<B> bs = new LinkedList<B>();

//get set
}

Java:
@Entity
public class B{
	@Id
	@GeneratedValue
	private Long id;

}

In meiner Bean habe ich folgendes:
Java:
@Named
@RequestScoped
public class AController{
	public void findA(){
		a= aService.searchEntityById(aID);

		a.getBs().add(new B());-->hier krachts
	}
Was ich nicht verstehe ist wenn ich sowas mache das klappt wunderbar nur wenn ich davor ein em.find mache klappt es nicht???:L
Java:
@Named
@RequestScoped
public class AController{
	public void findA(){
		A a= new A();
		a.getBs().add(new B());
               aService.searchEntityById(a);
	}


Hab die services und daos mal weg gelassen
 
Du musst erst noch die Liste laden, du hast Sie auf lazy stehen, dabei wird erst nachgeladen wenn die Liste benötigt wird, Wenn du dies auf eager stellst sollte das Problem weg sein, nur dann braucht der Ladevoragang natürlich auch länger beim 1. Objekt
 
Du musst erst noch die Liste laden, du hast Sie auf lazy stehen, dabei wird erst nachgeladen wenn die Liste benötigt wird, Wenn du dies auf eager stellst sollte das Problem weg sein, nur dann braucht der Ladevoragang natürlich auch länger beim 1. Objekt

Mit dem getter sollte die Liste geladen werden, oder?
 
LAZY würde ich immer expliziet nachladen Bsp:

mit einem inner join über JPA

Java:
"from BspClass c join fetch c.<feld>"

oder du verwendest Hibernate Criteria:
Java:
	DetachedCriteria crit = DetachedCriteria.forClass(BspClass.class);
        crit.setFetchMode("<feld>", FetchMode.JOIN);

Grüße
 
LAZY würde ich immer expliziet nachladen Bsp:

mit einem inner join über JPA

Java:
"from BspClass c join fetch c.<feld>"

oder du verwendest Hibernate Criteria:
Java:
	DetachedCriteria crit = DetachedCriteria.forClass(BspClass.class);
        crit.setFetchMode("<feld>", FetchMode.JOIN);

Grüße

Ja aber dann kann ich ja gleich Eager laden

EDIT: Ich glaube mit EclipseLink hatte ich solche Probleme nicht^^
 
Zuletzt bearbeitet von einem Moderator:
Kommt auf den Anwedungsfall an:

1. Die Assoziation beinhaltet wenig Elemente und du benötigst diese immer (User + alle seine Rollen) EAGER
2. Die Assoziation wird sehr selten gebraucht (User + alle seine Rechnungen) dann würde ich es nicht machen außer dir ist Performance völlig wurst.
3. EAGER geht immer nur für eine Collection in einer Klasse d.h. wenn du mehrere Collections in einer Klasse hast wirst du nicht drum rumkommen diese nachzuladen.


Grüße
 
Kommt auf den Anwedungsfall an:

1. Die Assoziation beinhaltet wenig Elemente und du benötigst diese immer (User + alle seine Rollen) EAGER
2. Die Assoziation wird sehr selten gebraucht (User + alle seine Rechnungen) dann würde ich es nicht machen außer dir ist Performance völlig wurst.
3. EAGER geht immer nur für eine Collection in einer Klasse d.h. wenn du mehrere Collections in einer Klasse hast wirst du nicht drum rumkommen diese nachzuladen.


Grüße

Ja die Anwendungsfälle sind mir klar.

Aber ich verstehe nicht warum ich alle einträge brauche um der liste was hinzuzufügen.
 
Das wiederrum liegt an deinem Design 😀

Stichwort: Bi-Direktional
Java:
public class A{

@OneToMany(mappedBy="a", fetch=FetchType.LAZY, cascade=Cascade.ALL)
private List<B> lists;

//getter & setter
}

public class B{

@ManyToOne(fetch=FetchType.LAZY)
private A a;

//getter & setter
}

public void createNewB(Long id){

A a = em.find(A.class,id);

//neues B
B b = new B();
b.setA(classA);//Referenz auf A setzen!
em.persist(b);
}

oder du machst es Uni-direktional (also gerichtet) verwendest nur @ManyToOne um die Referenz von A in B zusetzen. 😀 jetzt ist die Verwirrung Perfekt 🙂
 
Zuletzt bearbeitet:
Das wiederrum liegt an deinem Design 😀

Stichwort: Bi-Direktional
Java:
public class A{

@OneToMany(mappedBy="a", fetch=FetchType.LAZY, cascade=Cascade.ALL)
private List<B> lists;

//getter & setter
}

public class B{

@ManyToOne(fetch=FetchType.LAZY)
private A a;

//getter & setter
}

public void createNewB(Long id){

A a = em.find(A.class,id);

//neues B
B b = new B();
b.setA(classA);//Referenz auf A setzen!
em.persist(b);
}

oder du machst es Uni-direktional (also gerichtet) verwendest nur @ManyToOne um die Referenz von A in B zusetzen. 😀 jetzt ist die Verwirrung Perfekt 🙂

Ich hab eine undirektionale...
 
Ja aber dann kann ich ja gleich Eager laden
Der Unterschied ist, dass du mit fetch joins bzw. explizitem fetch mode entscheiden kannst, wann diese Assoziation gleich mitgeladen werden, idealerweise immer dann, wenn man sie benötigt, zwingerderweise immre dann, wenn ausserhalb der Session auf sie zugegriffen werden soll, dazu muss man die Use Cases kennen.
Kurz: Das ist ein Vorteil in Bezug auf Performance, kein Nachteil.

EDIT: Ich glaube mit EclipseLink hatte ich solche Probleme nicht^^
Hättest du dasselbe mit EclipseLink gemacht, hättest du dasselbe Problem 😉
Eager/Lazy Loading ist eigentlich immer ziemlich gleich 😉
 
Der Unterschied ist, dass du mit fetch joins bzw. explizitem fetch mode entscheiden kannst, wann diese Assoziation gleich mitgeladen werden, idealerweise immer dann, wenn man sie benötigt, zwingerderweise immre dann, wenn ausserhalb der Session auf sie zugegriffen werden soll, dazu muss man die Use Cases kennen.
Kurz: Das ist ein Vorteil in Bezug auf Performance, kein Nachteil.
Da es sich hier um einen Prototyp handelt wird die Performance (noch) keine Rolle spielen. Aber verstehen würde ich es trotzdem gerne =)

Hättest du dasselbe mit EclipseLink gemacht, hättest du dasselbe Problem 😉
Eager/Lazy Loading ist eigentlich immer ziemlich gleich 😉

Muss ich mal tesen wenn ich Zeit hab^^
 
Da es sich hier um einen Prototyp handelt wird die Performance (noch) keine Rolle spielen. Aber verstehen würde ich es trotzdem gerne =)
Nun ja, das gehört doch zu den Basics, Lazy Loading ist für Collections u.a. default, weil man einerseits verhindern möchte, das irgendwann die ganze DB im Ram steht, andererseits nicht allzuviele Objekte erzeugen möchte die man u.U. nicht braucht.
Wenn die Session offen ist, ist es "nur" ein perforamce Problem, denn wenn ich auf eine Lazy Collections zugreife während die Session offen ist, wird diese in dem Moment aus der DB nachgeladen, also ein weiteres SQL Statement abgesetzt, zusätzlich zum ersten um die Entity zu laden.
Mit Eager Loading/join fetch/explizitem fetch mode würde insgesamt nur 1 SQL Statement abgesetzt um die Entitiy und die Collection zu laden, aber mit eager loading ist das fix, mit fetch groups oder fetch mode kann die Relation auf lazy bleiben und wird im Bedarfsfall dann doch eager geladen.

Mit Lazy Loading und einer geschlossenen Session kracht es eben -> LazyInit Exception, du versuchst auf ein Attribut zuzugreifen das noch gar nicht geladen ist und nicht (lazy) nachgeladen werden kann weil die Session schon zu ist.

JDO unterstützt auch lazy/eager loading und fetch groups, selbes Prinzip, gehört wie gesagt zu den ORM Basics.
 
Ich glaube ich hab mich falsch ausgedrückt, ich bin eher verwirrt warum meine session zu ist.
 

Zurück
Oben