Question

I'm trying to use the Castle NHibernate Facility with the AutoTx Facility. As a test, I'm throwing an exception in the middle of my service, to make sure the transaction is rolled back. However, the data is still persisted in the database.

My service interface, IActivityService using the TransactionAttribute:

public interface IActivityService
{
    [Transaction]
    Activity CreateActivity(Activity activity);
}

The implementation of CreateActivity. I'm throwing an exception here, expecting the data added in AddActivity to be rolled back:

public virtual Activity CreateActivity(Activity activity)
{
    activityDAO.AddActivity(activity);
    throw new Exception("This should rollback the transaction");
    return activity;
}

Implementation of AddActivity. SessionManager is an injected ISessionManager.

public void AddActivity(Activity activity)
{
    using (ISession session = SessionManager.OpenSession())
    {
        session.Save(activity);
    }
}

Finally, here's how I'm configuring the windsor container. The NHibernateInstaller is straight from the guide, with my fluent nhibernate configuration swapped in:

container = new WindsorContainer().Install(FromAssembly.This());

// set up ISessionManager injection for DAOs
container
    .AddFacility<AutoTxFacility>()
    .Register(Component
        .For<INHibernateInstaller>()
        .ImplementedBy<NHibernateInstaller>()
        .LifeStyle.Singleton)
    .AddFacility<NHibernateFacility>(f => 
        f.DefaultLifeStyle = DefaultSessionLifeStyleOption.SessionPerWebRequest);

The configuration seemed fairly straightforward, but I can't figure out what I'm missing. Thanks for any help.

Was it helpful?

Solution

You do not show the class declaration code for the service implementation class, so you might have already done this, but if you want declarative transactions, you need to annotate the transaction class with the [Transactional] attribute.

[Transactional]    
public class ActivityServiceImpl {

    [Transaction]
    public Activity CreateActivity(Activity activity) {
        // ... implementation here
    }
}

If you do not include the [Transactional] attribute on the implementing class, the AutoTx facility does not know to create a wrapper for the class.

I tend to put the [Transaction] attribute on the implementing method, not in the interface definition. I don't know if it works annotating the interface method declaration.

One more thing you might need to try. I notice that when you are configuring your container, you are installing first, and then adding the AutoTx facility. I think you should add the facilities first before invoking your installers.

OTHER TIPS

At first you must have direct dependencies between Session Manager and Activity Service. Session manager should be injected into Activity Service. Only in this case the facility can affect NHibernate transaction.

    [Transactional]
    public class ActionService : IActionService
    {
        private ISessionManager _sessionManager;

        [Transaction]
        public void AddActivity(Activity activity)
        {
            using (ISession session = _sessionManager.OpenSession())
            {
                using (ITransaction tran = session.BeginTransaction())
                {
                        session.Save(activity);
                    tran.Commit();
                }
            }       
        }
        public ActionService(ISessionManager sessionManager)
    {
            _sessionManager = sessionManager;       
        }
    }
    _container.Register(Component.For<IActionService>()
            .ImplementedBy<ActionService>.LifestylePerWebRequest());

Also check that you are using same life styles for SessionManager, Server, DAOs and other dependent objects.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top