Lazy loading with NHibernate Castle Facility
Asked Answered
K

2

5

Do I have to close the ISession's that are generated by Castle's ISessionManager for NHibernate? How do I handle transactions with those ISession's? I'm still quite new to NHibernate.

Edit: I would like to have lazy loading but I get this message:

Initializing[failed to lazily initialize a collection of role: , no session or session was closed"

Here is my generic Repository which I inherit to implement specific instances.

[Transactional]
public class Repository<TKey, TModel>
    : IRepository<TKey, TModel>
    where TKey : IComparable
    where TModel : class
{
    private readonly ISessionManager _sessionManager;

    protected ISession Session { get { return _sessionManager.OpenSession(); } }

    public Repository(ISessionManager sessionManager)
    {
        _sessionManager = sessionManager;
    }
    #region IRepository<TKey,TModel> Members

    public virtual TModel Select(TKey key)
    {
        using (var session = _sessionManager.OpenSession())
        {
            return session.Get<TModel>(key);
        }
    }

    public virtual IList<TModel> SelectWhere(Func<TModel, bool> query)
    {
        using (var session = Session)
        {
            return session.Linq<TModel>().Where(query).ToList();
        }
    }

    public virtual TModel Single(Func<TModel, bool> query)
    {
        using (var session = Session)
        {
            return session.Linq<TModel>().SingleOrDefault(query);
        }
    }

    public virtual TModel First(Func<TModel, bool> query)
    {
        using (var session = Session)
        {
            return session.Linq<TModel>().FirstOrDefault(query);
        }
    }

    public virtual IList<TModel> All()
    {
        using (var session = Session)
        {
            return session.Linq<TModel>().ToList();
        }
    }

    [Transaction(TransactionMode.Requires)]
    public virtual void Store(TModel entity)
    {
        using (var session = Session)
        {
            session.SaveOrUpdate(entity);
        }
    }

    [Transaction(TransactionMode.Requires)]
    public virtual void Store(IEnumerable<TModel> entities)
    {
        using (var session = Session)
        {
            foreach (TModel entity in entities)
                session.SaveOrUpdate(entity);
        }
    }


    [Transaction(TransactionMode.Requires)]
    public virtual void Remove(TModel entity)
    {
        using (var session = Session)
        {
            session.Delete(entity);
        }

    }

    public virtual void Remove(Func<TModel, bool> query)
    {
        IEnumerable<TModel> entities = SelectWhere(query);
        Remove(entities);
    }

    [Transaction(TransactionMode.Requires)]
    public virtual void Remove(IEnumerable<TModel> entities)
    {
        using (var session = Session)
        {
            foreach (TModel entity in entities)
                session.Delete(entity);
        }
    }

    #endregion
}

public class Repository<TModel>
    : Repository<Guid, TModel>, IRepository<TModel>
    where TModel : class
{
    public Repository(ISessionManager sessionManager) : base(sessionManager) { }
}

public class Repository
    : Repository<ulong, object>, IRepository
{
    public Repository(ISessionManager sessionManager) : base(sessionManager) { }
}

Here is a sample invoking of that repository:

IUserRepository userRepository = new UserRepository(); // This is actually provided by my IoC

var users = userRepository.All();
foreach (var user in Users)
{
    foreach (var picture in user.Pictures)
    {
        // I get exceptions when I do stuff like this.
    }
}
Kratz answered 13/7, 2009 at 3:55 Comment(0)
H
6

Yes, always dispose the ISession. See the docs on ISessionManager usage.

For transactions, consider using the Automatic Transaction Facility.

The SessionManager is ATM-aware so it will dispose the ISession smartly when it needs to, taking transactions into account, even when you apparently have disposed the ISession.

Here's a quick & dirty sample app that uses ASP.NET MVC + Castle Automatic Transaction Facility + NHibernate facility

Headman answered 13/7, 2009 at 13:19 Comment(10)
What you really need is some sample code. See svn.castleproject.org:8080/svn/castle/trunk/Samples/MindDump and the tests: svn.castleproject.org:8080/svn/castle/trunk/Facilities/…Headman
Can you point me to a file that shows lazy loading functioning?Kratz
do you have the sessionwebmodule registered? mail-archive.com/[email protected]/…Headman
Are you using the ATM? Is your transactional class decorated with [Transactional] and [Transaction]? Please post some code.Headman
The repository code looks good. Could you post a method where you invoke the repository?Headman
I updated to include the specific repository and utilization.Kratz
I'm done guessing... so I created a quick & dirty sample app (asp.net mvc + ATM + NH facility) so you can compare with your code: code.google.com/p/mausch/source/detail?r=215Headman
Try the castle group: groups.google.com/group/castle-project-users . Link back here so they don't have to start diagnosing from scratch.Headman
For future reference, here's the thread: groups.google.com/group/castle-project-users/browse_thread/…Headman
Thanks. I figured out my problem. The Windsor Container for it, wasn't set to static and hence it would recreate it.Kratz
F
0

We use transactions with using statements to handle the disposing.

public void Save<K>(K entity)
        {

            if (entity == null)
                throw new ArgumentNullException("item", "The item being saved cannot be null.");

            using (ISession session = GetSession())
            {
                using (ITransaction tx = session.BeginTransaction())
                {
                    session.SaveOrUpdate(entity);
                    tx.Commit();
                }
            }
        }

I will still get the lazy loading error if I am accessing objects after making a modification in the same action. I have fixed the error by not accessing the objects after a save. Here's an explination: NHibernate.LazyInitializationException

I believe it is due to not saving the hierarchy correctly. I haven't tested it, but maybe saving the parent objects if you wish to access them will fix the issue. Simply putting the information I needed to access after the save into local variables before the save seemed to correct my issue.

Flaherty answered 16/7, 2009 at 14:14 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.