NHibernate - Лучшая практика для избранных

A иметь действие в моем приложении MVC, которое имеет id и возвращает имя человека.

Что для этого лучше всего? Я следую советам NHProf, но код звучит для меня немного странно или что-то в этом роде.

using (var session = Helper.SessionFactory.OpenStatelessSession())
{
    using (var tran = session.BeginTransaction(IsolationLevel.ReadCommitted))
    {
        return session.Query<Person>().Where(x => x.Id == id).Select(x => x.Name).SingleOrDefault();
        tran.Rollback();
    }
}

person Zote    schedule 10.05.2012    source источник
comment
Я не могу понять, почему он предлагает транзакцию ...   -  person Felice Pollano    schedule 10.05.2012
comment
Я бы не стал использовать OpenStatelessSession сеанс без сохранения состояния предназначен для массовых сценариев и игнорирует кеш L1. Вместо выполнения запроса linq я бы просто вызвал .Load<Person>(1) или .Get<Person>(1), который выражает намерение больше, чем запрос linq.   -  person Andreas    schedule 10.05.2012


Ответы (3)


На странице предупреждений NHProf это довольно хорошо объясняется, я думаю -

http://nhprof.com/Learn/Alerts/DoNotUseImplicitTransactions

По сути, это говорит о том, что если вы не управляете транзакциями самостоятельно, база данных будет создавать «неявную транзакцию» и автоматически фиксировать каждый оператор, включая запросы. Заблуждение состоит в том, что транзакции полезны только для операций вставки / обновления.

В приведенном выше примере это не проблема, поскольку ваша транзакция в любом случае выполняет только один оператор. Однако если ваш метод выполнял несколько операторов, было бы неплохо заключить их в транзакцию.

person richeym    schedule 10.05.2012
comment
Хорошо, но для простых методов я должен следовать NHProf и создавать транзакцию или нет? - person Zote; 10.05.2012
comment
Ответ верен лишь частично, вы должны всегда искажать запрос к базе данных в транзакции, и это действительно будет проблемой, даже если вы выполните один оператор. Неявные транзакции стоят дорого! и NH не будет использовать кэш L2 без транзакции. - person Andreas; 10.05.2012

Вот как я подхожу к этому выбору:

    using (var session = Helper.SessionFactory.OpenStatelessSession())
    using (var tran = session.BeginTransaction(IsolationLevel.ReadCommitted))
    {
        try
        {
            string personName = session.Query<Person>()
            .Where(x => x.Id == id)
            .Single(x => x.Name);

            tran.Commit();
            return personName;
        }
        catch(Exception ex)
        {
            // handle exception
            tran.Rollback();
        }
    }

Этот SO-ответ дает хороший совет по работе с транзакциями:

NHibernate - действительно ли необходимо ITransaction.Commit?

Что касается вашего LINQ, это интересная статья о том, как не подходить к запросам с использованием синтаксиса стиля метода расширения:

http://compiledexperience.com/blog/posts/how-not-to-use-linq

person Peadar Doyle    schedule 10.05.2012
comment
-1 для отлова всего, выполнения лишней работы (с использованием и попытки catch). - person Andreas; 10.05.2012
comment
@Andreas, насколько мне известно, using не имеет способа обработать выброшенное исключение, и выбор состоит в том, чтобы использовать повторную попытку или удалить вручную. Также как бы вы реализовали обработку ошибок в этом случае, поскольку существует ряд уровней, которые могут вызывать ошибку (NHibernate, ADO.NET, LINQ). - person Peadar Doyle; 11.05.2012
comment
stackoverflow.com/questions/6418992/ и для исключений stackoverflow.com/ questions / 426346 / http://stackoverflow.com/questions/114658/catching-base-exception-class-in-net blogs.msdn.com/b/ericlippert/archive/2008/09/10/ и не говорите мне, что вы можете правильно обрабатывать stackoverflow, вне памяти exc с вашим tran.Rollback();. - person Andreas; 11.05.2012
comment
Спасибо за ссылки, я не знал, что транзакции неявно откатывались. Также я должен был поместить исключение // handle после Rollback (), так как я задумал его как место для обработки ошибок. Я ценю то, что вы говорите о перехвате всей обработки исключений, и, вероятно, это не лучшее, что можно здесь сделать. - person Peadar Doyle; 11.05.2012

не создавайте несколько сеансов по одному HTTP-запросу, в идеале вам нужно открыть сеанс и соответствующую транзакцию в области запроса и использовать этот сеанс во всех ваших действиях.

Вот сообщение в блоге, объясняющее, как этого добиться: http://hackingon.net/post/NHibernate-Session-Per-Request-with-ASPNET-MVC.aspx

Я бы предложил использовать контейнер IOC и создать класс, который создает для вас сеанс, и ограничить этот класс областью запроса.

В Интернете есть множество ресурсов, которые помогут решить эту проблему .. Погуглите ..

person Baz1nga    schedule 10.05.2012
comment
Хотя один сеанс на запрос - это хороший совет, это не жесткое и быстрое правило, а наличие одной транзакции на запрос - плохой совет, простой и понятный. - person Spivonious; 22.07.2016