Visualizzazione dei risultati da 1 a 4 su 4
  1. #1

    [RISOLTO] - J2EE - errore (failed to lazily initialize a collection of role...)

    Ciao a tutti,
    ho un problema con il mio progetto in J2EE, allora vi riporto i 2 EntityBean di interesse

    ENTITY TRAINER
    codice:
    package com.lesson.entities;
    
    //Import
    import java.io.Serializable;
    import javax.persistence.Entity;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    //Relational imports
    import javax.persistence.OneToMany;
    
    //Other imports
    import java.util.List;
    
    @SuppressWarnings("serial")
    @Entity	
    @Table(name="trainer")
    public class Trainer implements Serializable
    {
    	//Variables
    	private int trainerID;
    	private String name;
    	private String surname;
    	private String email;
    	private String password;
    	private List<Course> taughtCourseList;
    	private List<Notification> unreadNotificationList;
    	
    	//Getters and Setters
    	@Id
    	public int getTrainerID()
    	{
    		return trainerID;
    	}
      ........ 
      ........


    ENTITY COURSE
    codice:
    package com.lesson.entities;
    
    //Import
    import java.io.Serializable;
    import javax.persistence.Entity;
    import javax.persistence.Id;
    import javax.persistence.Table;
    
    //Relational imports
    import javax.persistence.ManyToOne;
    //import javax.persistence.ManyToMany;
    import javax.persistence.OneToMany;
    
    //Other imports
    import java.util.List;
    
    @SuppressWarnings("serial")
    @Entity	
    @Table(name="course")
    public class Course implements Serializable
    {
    	//Variables
    	private int courseID;
    	private String title;
    	private String field;
    	private Trainer trainer;
    	private List<Student> registeredStudentList;
    	private List<Material> courseMaterialList;
    	private List<Test> courseTestList;
    	
    	//Getters and Setters
    	@Id
    	public int getCourseID()
    	{
    		return courseID;
    	}
    .......
    .......
    Allora quando il client vuole creare un nuove Professore, utilizza il seguente metodo:
    codice:
    package com.lesson.controllers;
    
    
    import java.util.ArrayList;
    import java.util.Hashtable;
    import java.util.List;
    
    import com.lesson.entities.*;
    
    import javax.ejb.EJB;
    import javax.ejb.Stateless;
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import javax.persistence.EntityManager;
    import javax.persistence.NoResultException;
    import javax.persistence.NonUniqueResultException;
    import javax.persistence.PersistenceContext;
    import javax.persistence.Query;
    
    import org.jboss.ejb3.annotation.RemoteBinding;
    
    @Stateless 
    @RemoteBinding(jndiBinding="TrainerManagerRemote") 
    public class TrainerManagerBean implements TrainerManagerRemote 
    {
    
    	@PersistenceContext(unitName="lesson")
    	private EntityManager manager;
    	@EJB
    	private CourseManagerLocal cml;
    	
    	public boolean createTrainer(TrainerRequest ntr) throws Exception
    	{
    		if (ntr.getEmail() == null || ntr.getName() == null || ntr.getPassword() == null ||
    				ntr.getSurname() == null || ntr.getTrainerID() <= 0) 
    			throw new IllegalArgumentException("Invalid null fields in patientRequest"); 
    		
    		//Check if trainer is already into DB
    		Query q = manager.createQuery("select t from Trainer as t where t.trainerID = ?1");
    		q.setParameter(1, ntr.getTrainerID());
    		Trainer t = null;
    		try
    		{
    			t = (Trainer)q.getSingleResult();
    			if (t != null ) throw new NonUniqueResultException("Trainer "+ ntr.getTrainerID() +"already present in DB");
    		} catch(NoResultException ex) {}
    		
    		t = new Trainer();
    		t.setTrainerID(ntr.getTrainerID());
    		t.setName(ntr.getName());
    		t.setSurname(ntr.getSurname());
    		t.setEmail(ntr.getEmail());
    		t.setPassword(ntr.getPassword());
    		List<Course> courseList = new ArrayList<Course>();
    		t.setTaughtCourseList(courseList);
    		List<Notification> notificationList = new ArrayList<Notification>();
    		t.setUnreadNotificationList(notificationList);
    		
    		manager.persist(t);		
    		return true;
    	}
    Considerate pure il "TrainerRequest come se fosse un oggetto di tipo Trainer...

    Ora viene il problema:
    Mettiamo che venga registrato un nuovo corso tenuto dal professore appena creato. Come posso fare per inserire nella List<Course> presente nell'entity Trainer (professore) il nuovo corso da lui insegnato?

    Inizialmente ho pensato di modificare quella lista all'atto della creazione di un nuovo corso, quindi dal SessionBean di Course tramite:

    codice:
    public void setCourse(CourseRequest courseRequest) throws Exception
    	{
    		Course c = new Course();
    		c.setCourseID(courseRequest.getCourseID());
    		c.setCourseMaterialList(null);
    		c.setCourseTestList(null);
    		c.setField(courseRequest.getField());
    		c.setRegisteredStudentList(null);
    		c.setTitle(courseRequest.getTitle());
    		
    		// Retrieve PatientManager
    		TrainerManagerRemote tmr;
    		try
    		{
    			InitialContext ctx = new InitialContext();
    			tmr = (TrainerManagerRemote) ctx.lookup("TrainerManagerRemote");	
    		}
    		catch(Exception ne)
    		{
    			ne.printStackTrace();
    			throw new Exception("Cannot instantiate Trainer Manager", ne);
    		}
    		
    		Trainer trainer = tmr.getTrainerData(courseRequest.getTrainerID());
    		if(trainer == null) throw new Exception("Trainier with id=" + courseRequest.getTrainerID() + " does not exist");
    		c.setTrainer(trainer);
    		manager.persist(c);
    		List<Course> temp = new ArrayList<Course>();
    		temp.add(c);
    		trainer.setTaughtCourseList(temp);
    		tmr.updateTrainer(trainer);
    	}
    L'esecuzione non sembra generare eccezioni...tuttavia quando dal client cerco di accedere alla lista sopra citata ottengo...

    codice:
    IWAV0055I Java Bean lesson.client.Main started with the main method
    org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: com.lesson.entities.Trainer.taughtCourseList, no session or session was closed
    	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:380)
    	at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:372)
    	at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:119)
    	at org.hibernate.collection.PersistentBag.size(PersistentBag.java:248)
    	at lesson.client.Main.getTrainer(Main.java:116)
    	at lesson.client.Main.main(Main.java:31)
    	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:597)
    	at org.eclipse.ve.internal.java.vce.launcher.remotevm.JavaBeansLauncher.main(JavaBeansLauncher.java:79)
    Il Client è il seguente, il metodo che uso per leggere i dati di un Trainer è getTrainerData(...), il quale generà però l'errore sopra riportato.
    codice:
    package lesson.client;
    
    import java.util.ArrayList;
    import java.util.Hashtable;
    import java.util.List;
    
    import javax.naming.Context;
    import javax.naming.InitialContext;
    import com.lesson.controllers.*;
    import com.lesson.entities.*;
    
    public class Main 
    {
    
    	static TrainerManagerRemote pm;
    	
    	public static void main(String[] args) 
    	{
    		try 
    		{
    			Context jndiContext = null;
    
    			jndiContext = getInitialContext();
    			Object ref = jndiContext.lookup("TrainerManagerRemote");
    			pm = (TrainerManagerRemote)ref;
    			
    			//logIn();
    			//createTrainer();
    			//createCourse();
    			//updateTrainer();
    			getTrainer();
    			
    			
    		} catch (Exception e) { e.printStackTrace();}
    
    	}
    	
    	public static void logIn()
    	{
    		try 
    		{
    			if(pm.logIn(11111, "111111"))
    			System.out.println("[DEBUG]--Logged");
    			else
    				System.out.println("[DEBUG]--Not Logged");
    	
    		} catch (Exception e) {}
    
    	}
    	
    	public static void updateTrainer()
    	{
    		Trainer t = new Trainer();
    		t.setEmail("cristianmandelli@gmai.com");
    		t.setName("Cristian");
    		t.setSurname("Mandelli");
    		t.setPassword("02041985");
    		t.setTrainerID(1111);
    		t.setUnreadNotificationList(null);
    		List<Course> list = new ArrayList<Course>();
    		list.add(pm.getCourseData(1234));
    		t.setTaughtCourseList(list);
    		
    		try 
    		{
    			pm.updateTrainer(t);
    		
    		} catch (Exception e) 
    			{
    				e.printStackTrace();
    			}
    	}
    	
    	public static void createTrainer()
    	{
    		TrainerRequest t = new TrainerRequest(2222, "Deborah", "Zamponi", "deborah.zamponi@gmail.com", "110585");
    		try 
    		{
    			if(pm.createTrainer(t))
    			System.out.println("[DEBUG]--Trainer created");
    							
    		} catch (Exception ex) 
    			{
    				ex.printStackTrace();
    			}
    	}
    	
    	public static void createCourse()
    	{
    		
    		CourseRequest c = new CourseRequest(1234, "SoftwareEngeneering 1", "Computer Science", 2222);
    		try 
    		{
    			if(pm.createCourse(c));
    			System.out.println("[DEBUG]--Course created");
    			
    		} catch (Exception ex) 
    			{
    				ex.printStackTrace();
    			}
    	}
    	
    	public static void getTrainer()
    	{
    		Trainer t = null;
    		try
    		{
    			t = pm.getTrainerData(2222);
    		} catch (Exception ex)
    			{
    				ex.printStackTrace();
    			}
    		
    		if(t != null)
    		{
    			System.out.println("Courses List:" + t.getTaughtCourseList().size());
    		}
    		
    	}
    	
    	static public Context getInitialContext() throws Exception
    	{
    		Hashtable<String,String> env = new Hashtable<String,String>();
    		env.put(Context.INITIAL_CONTEXT_FACTORY,"org.jnp.interfaces.NamingContextFactory");
    		env.put(Context.PROVIDER_URL,"localhost:1099");
    
    		return new InitialContext(env);
    	}
    
    }

    qualche suggerimento circa dove sia il mio errore??

    Cristian
    Cristian

  2. #2
    Ho praticamente risolto da solo leggendo una parte della documentazione J2EE...

    Il problema è il seguente. Quando si definisce la relazione 1..N tra le due tabelle si utilizza l'annotazione @OneToMany. Questa annotazione ha diversi parametri tra i quali il parametro "fetch". Nella relazione @OneToMany il valore di default di questo parametro è LAZY. Ciò significa che nel momento in cui si carica in memoria l'entity Utente non viene caricata automaticamente in memoria la lista dei numeri di telefono. E' un discorso di ottimizzazione che implica l'utilizzo di memoria da una parte ed il numero di accessi al database dall'altro. Per risolvere il mio problema basta impostare il valore del parametro fetch = EAGER, ovvero

    @OneToMany(fetch = FetchType.EAGER)

    Cristian
    Cristian

  3. #3
    Anche tu alle prese con Lesson...

    Nell'ottica di poche centinaia di record può andare ma non è il massimo, con una query ben strutturata (EJBQL) puoi ottenere la stessa collezione di elementi.



    P.S.
    Se non vuoi trovarti con duplicati nelle relazioni OneToMany o ManyToMany usa Set al posto di List...
    Forrest
    Mail Me

  4. #4
    Originariamente inviato da Mandels85
    Ho praticamente risolto da solo leggendo una parte della documentazione J2EE...

    Il problema è il seguente. Quando si definisce la relazione 1..N tra le due tabelle si utilizza l'annotazione @OneToMany. Questa annotazione ha diversi parametri tra i quali il parametro "fetch". Nella relazione @OneToMany il valore di default di questo parametro è LAZY. Ciò significa che nel momento in cui si carica in memoria l'entity Utente non viene caricata automaticamente in memoria la lista dei numeri di telefono. E' un discorso di ottimizzazione che implica l'utilizzo di memoria da una parte ed il numero di accessi al database dall'altro. Per risolvere il mio problema basta impostare il valore del parametro fetch = EAGER, ovvero

    @OneToMany(fetch = FetchType.EAGER)

    Cristian
    Ho il tuo stesso problema...come lo hai risolto? Nei file di mapping delle classi hbm.xml dove la imposti questa proprietà? Nel tag <one-to-many> mi sembra che non è presente tale attributo.

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.