views:

2609

answers:

4

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.
    }
}
+3  A: 

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

Mauricio Scheffer
How do I do lazy loading?
Daniel A. White
What you really need is some sample code. See http://svn.castleproject.org:8080/svn/castle/trunk/Samples/MindDump/ and the tests: http://svn.castleproject.org:8080/svn/castle/trunk/Facilities/NHibernateIntegration/Castle.Facilities.NHibernateIntegration.Tests/
Mauricio Scheffer
Can you point me to a file that shows lazy loading functioning?
Daniel A. White
do you have the sessionwebmodule registered? http://www.mail-archive.com/[email protected]/msg01663.html
Mauricio Scheffer
Yep. It should be there.
Daniel A. White
Are you using the ATM? Is your transactional class decorated with [Transactional] and [Transaction]? Please post some code.
Mauricio Scheffer
I am using ATM.
Daniel A. White
The repository code looks good. Could you post a method where you invoke the repository?
Mauricio Scheffer
I updated to include the specific repository and utilization.
Daniel A. White
Mauricio Scheffer
I thank you for your help, but I'm still stuck.
Daniel A. White
Try the castle group: http://groups.google.com/group/castle-project-users . Link back here so they don't have to start diagnosing from scratch.
Mauricio Scheffer
For future reference, here's the thread: http://groups.google.com/group/castle-project-users/browse_thread/thread/ca664d44fa1829cb
Mauricio Scheffer
Thanks. I figured out my problem. The Windsor Container for it, wasn't set to static and hence it would recreate it.
Daniel A. White
A: 

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: http://stackoverflow.com/questions/1125988/nhibernate-lazyinitializationexception/1126997#1126997

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.

Josh
A: 

dummy - i want to end the bounty.

Daniel A. White
A: 

I have the similar issue so how did you solve it?

Marcus
see the comments on the first message
Mauricio Scheffer
I can't get this to work with my code and this is how I create and register my windsorcontainer http://pastie.org/645574 and this is my windsorcontrollerfactory http://pastie.org/645580
Marcus