Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle NHibernate session lifetime using services?

In this question I asked about NHibernate session lifetime. I'm using a desktop application, but with client/server separation, so the conclusion is that I will use one session per server request, as the server side is where all the NHibernate magic happens.

My problem now is how to handle it. I've had problems before with loading of referenced data when the session is prematurely closed. The problem is that I see the following on my referenced classes when debugging - hence the referenced data isn't loaded yet:

base {NHibernate.HibernateException} = {"Initializing[MyNamespace.Foo#14]-failed to lazily initialize a collection of role: MyNamespace.Foo.Bars, no session or session was closed"}

From what I understand it doesn't load all even though I commit the transaction. So I've learned that I need to keep my session open for a while, but how long?

My question is basically if I'm handling the lifetime properly, or what I should change to be on the right track. Honestly I can't see how this can be wrong, so what I'd really like is a function call to ensure that the referenced data is fetched. I'm not using lazy loading, so I thought they would be loaded immediately..?

Current architecture: Using a "service behavior" class that does the transaction. This is IDisposable, so the service itself it using a using-clause around it. The NHibernateSessionFactory provides a static factory which hence will be resused.

// This is the service - the function called "directly" through my WCF service. 
public IList<Foo> SearchForFoo(string searchString)
{
    using (var serviceBehavior = new FooServiceBehavior(new NhibernateSessionFactory()))
    {
        return serviceBehavior.SearchForFoo(searchString);    
    }                        
}

public class FooServiceBehavior : IDisposable
{
    private readonly ISession _session;

    public FooServiceBehavior(INhibernateSessionFactory sessionFactory)
    {
        _session = sessionFactory.OpenSession();                
    }

    public void Dispose()
    {
        _session.Dispose();
    }

    public IList<Foo> SearchForFoo(string searchString)
    {           
        using (var tx = _session.BeginTransaction())
        {
            var result = _session.CreateQuery("from Foo where Name=:name").SetString("name", searchString).List<Name>();
            tx.Commit();
            return result; 
        }
    }
like image 790
stiank81 Avatar asked Jan 08 '10 13:01

stiank81


1 Answers

It turns out I'm doing lazy loading after all. I had the following mapping:

public class FooMapping : ClassMap<Foo>
{
    public FooMapping()
    {
        Not.LazyLoad();
        Id(c => c.Id).GeneratedBy.HiLo("1");
        Map(c => c.Name).Not.Nullable().Length(100);
        HasMany(x => x.Bars).Cascade.All();
    }
}

I assumed the Not.LazyLoad() disabled lazy loading, but apparently not for referenced objects. I added lazy loading on the reference, and this seems to have fixed the issue.

public class FooMapping : ClassMap<Foo>
{
    public FooMapping()
    {
        Not.LazyLoad();
        Id(c => c.Id).GeneratedBy.HiLo("1");
        Map(c => c.Name).Not.Nullable().Length(100);
        HasMany(x => x.Bars).Not.LazyLoad(); // <----------
    }
}

Thanks for your time, and I'll still be glad to see your opinions to whether my given structure is reasonable.

like image 117
stiank81 Avatar answered Sep 28 '22 05:09

stiank81