nHibernate, LazyLoading und LazyInitializationException



  • Hi.

    (Ich halte die Erklärungen relativ kurz. Wer mit nHibernate vertraut ist wird das Problem sofort verstehen)

    Außerhalb einer nHibernate-Session funktioniert LazyLoading nicht. Die Session will ich nicht offen halten (Winforms-Anwendung) und suche jetzt eine andere Lösung.

    //Die Entitäten. Benutzer und Kommentare von diesem Benutzer z.B. in einem Forum (Fantasiecode).
    //Es besteht eine one-to-many-Beziehung aus Sicht des Users.
    public class User
    {
    	public virtual int Id { get; set; }
    	public virtual string NickName { get; set; }
    
    	private ISet<Comment> comments = new HashedSet<Comment>();
        public virtual ISet<Comment> Comments { get { return comments; } set { comments = value; } }
    }
    
    public class Comment
    {
    	public virtual int Id { get; set; }
    	public virtual string Text {get; set;}
    }
    
    //////////////////////////////////////////////////////////////////////////////////////////
    
    //Verwendung in der GUI
    
    var list = userStorage.GetAll(); //Alle User laden.
    foreach (User user in list)
    {
    	Console.WriteLine(user.Nickname); //Klappt
    
    	Console.WriteLine(user.comments.Count);  //LazyInitializationException
    }
    

    Das XML-Mapping ist trivial und erspare ich euch (LazyLoading ist default).

    Die comments sollen "Lazy" geladen werden. Das geht aber schief weil nHibernate aus mir nicht ersichtlichen Gründen nicht
    in der Lage ist, selbstständig eine neue Session zu öffnen.

    Hier meine unschöne Lösung:

    //Code für userStorage			   
    public class GenericStorage<Entity> where Entity : class
    {
    	public virtual void Lock(Entity entity, Action action)
    	{
    		using (ISession session = sessionFactory.OpenSession())
    		{
    			session.Lock(entity, NHibernate.LockMode.None);
    			action();
    		}
    	}
    }
    
    //Wieder in der GUI		
    var list = userStorage.GetAll();
    foreach (User user in list)
    {
    	Console.WriteLine(user.Nickname);
    
    	userStorage.Lock(user, () =>
    	{
    		Console.WriteLine(user.comments.Count);
    	}
    }
    

    Die Lösung ist also, die user-Objekte im "detached"-Zustand wieder explizit in den "persistent"-Zustand zu überführen.
    Damit ziehen sich Implementierungsdetails der Datenschicht bis zur GUI durch!Das kann doch nicht die Lösung sein.

    Hat jemand eine bessere Lösung? (Lazy-Loading ist erwünscht! Eine andere Fetching-Strategie bringt mir im Anwendungsfall nichts)

    Danke, µ


Anmelden zum Antworten