Класс репозитория NHibernate - 1. Обработка с транзакцией | 2. Как начать сеанс - PullRequest
0 голосов
/ 31 октября 2011

Привет, я начинаю изучать NHibernate, и теперь я пытаюсь создать собственный класс репозитория для NHibernate.

Я нашел много статей на эту тему.Я выбрал этот урок: http://dotnetslackers.com/Community/blogs/antrad/archive/2008/10/25/about-repository-pattern-and-nhibernate.aspx

Я немного запутался, как справиться с транзакцией в репозитории.

У меня есть интерфейс репозитория:

public interface IRepository<T> where T : class
{
    void Commit();
    void RollBack();
    void BeginTransaction();
    //...
}

У меня вопрос, почемуХорошая транзакция начала в классе конструктора репозитория.

Эта часть кода взята из блога сверху.

public class NHibRepository<T> :IRepository<T> 
    where T : class
{
    #region Private fields

    private ISession _session;

    #endregion

    #region Constructor

    public NHibRepository(ISession session)
    {
        _session = NHibernateSessionManager.Instance.GetSession();

        //why begin transaction where???
        _session.BeginTransaction();
    }

    #endregion


    #region Trans

    public void Commit()
    {
        if (session.Transaction.IsActive)
        {
            session.Transaction.Commit();
        }
    }

    public void Rollback()
    {
        if (session.Transaction.IsActive)
        {
            session.Transaction.Rollback();
            session.Clear();
        }
    }

    public void BeginTransaction()
    {
        Rollback();
        session.BeginTransaction();
    }

    #endregion


}

Я обновляю этот репозиторий и теперь использую это решение:

public class NHibRepository<T> :IRepository<T> 
        where T : class
    {
        #region Private fields

        private ISession _session;

        #endregion

        #region Constructor

        public NHibRepository(ISession session)
        {
            _session = session;
        }

        #endregion


        #region Trans

        public void Commit()
        {
            using (var trans=_session.BeginTransaction())
            {
                trans.Commit();
            }
        }

        public void RollBack()
        {
            using (var trans = _session.BeginTransaction())
            {
                trans.Rollback();
            }
        }

        public void BeginTransaction()
        {
            throw new NotImplementedException();
        }

        #endregion


    }

Мой первый вопрос: какое решение лучше и почему?или что правильно, почему?


И мой второй вопрос, как открыть сеанс для класса репозитория, теперь я использую этот вспомогательный класс:

  public class NHibeHelper
    {
        private static ISessionFactory _sessionFactory;

        private static ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                    InitializeSessionFactory();

                return _sessionFactory;
            }
        }

        private static void InitializeSessionFactory()
        {

            _sessionFactory = Fluently.Configure()
                .Database(MsSqlConfiguration.MsSql2008
                              .ConnectionString(
                                   @"Server=Zues\SQLEXPRESS;Database=TEST;Trusted_Connection=True;")
                                  )

                .Mappings(m => m.FluentMappings.AddFromAssemblyOf<UserMap>().Conventions.Add(DefaultCascade.All()))


                .ExposeConfiguration(cfg => new SchemaUpdate(cfg).Execute(true, true))

                .BuildSessionFactory();
        }

        public static ISession OpenSession()
        {
            return SessionFactory.OpenSession();
        }
    }

При использовании так:

 _userRepo = new NHibRepository<User>(NHibeHelper.OpenSession());

1 Ответ

1 голос
/ 31 октября 2011

Рассматривая два варианта управления транзакциями, которые у вас есть, у них действительно есть проблемы.

В примере 1 транзакция не обязательно удаляется, и вы также связываете время жизни транзакции с временем жизни репозитория. Это не обязательно плохо, но если вы не используете контейнер IoC или какой-либо другой метод, чтобы гарантировать, что хранилище будет воссоздано для каждой операции базы данных, вы сможете выполнить коммит только один раз, и последующие коммиты, вероятно, потерпят неудачу.

Пример 2, к сожалению, не будет работать вообще - в Commit / RollBack вы каждый раз начинаете новую транзакцию. Особенно в случае RollBack, если он вызывался из внешнего кода в контексте транзакции, все, что вам нужно сделать, - это запустить новую вложенную транзакцию, а затем немедленно откатить ее. К сожалению, не очень полезно.

Мое личное решение вашего первого вопроса - отвести управление транзакциями от хранилища, используя окружающие транзакции в System.Transactions. Таким образом, у вас все еще есть разделение, так как окружающие транзакции не зависят от провайдера, но также у вас есть больший контроль над тем, какие из многих операций с репозиторием, которые вы можете выполнять, будут задействованы в транзакции, а не всегда будете использовать модель с одной транзакцией на операцию. , См. http://msdn.microsoft.com/en-us/magazine/cc163527.aspx для получения дополнительной информации.

Что касается вашего второго вопроса, я очень рекомендую заглянуть в контейнер IoC, такой как Castle Windsor или Unity. Вспомогательный класс, который у вас есть, гораздо лучше, чем перестройка фабрики сессий и тому подобное каждый раз, но с помощью контейнера IoC вы можете очень легко убедиться, что время жизни вашего объекта сеанса именно то, что вы хотите. Например, в ряде служб WCF Per-Call, над которыми я работаю, я использую Castle Windsor, чтобы гарантировать, что сеанс создается (и внедряется в хранилище), когда начинается операция WCF, и удаляется (вместе с хранилищем). ) когда это заканчивается.

...