Предоставление Ninject управления моим состоянием транзакций, практика
Я разрешаю Ninject управлять состоянием ISession
и ITransaction
в Fluent nHibnerate со следующим методом регистрации - мне интересно, достаточно ли контролировать транзакции или нужно ли это помещать в другое место.
Мысль о том, что каждый ISession
создается по запросу и что Ninject обрабатывает фиксацию всего, что было сделано во время этого запроса.
public class SessionModule : Ninject.Modules.NinjectModule
{
private static ISessionFactory sessionFactory;
public override void Load()
{
Bind<ISessionFactory>()
.ToMethod(c => CreateSessionFactory())
.InSingletonScope();
Bind<ISession>()
.ToMethod(c => OpenSession())
.InRequestScope()
.OnActivation(session =>
{
session.BeginTransaction();
session.FlushMode = FlushMode.Commit;
})
.OnDeactivation(session =>
{
if (session.Transaction.IsActive)
{
try
{
session.Flush();
session.Transaction.Commit();
}
catch
{
session.Transaction.Rollback();
}
}
});
}
/// <summary>
/// Create a new <see cref="NHibernate.ISessionFactory"/> to connect to a database.
/// </summary>
/// <returns>
/// A constructed and mapped <see cref="NHibernate.ISessionFactory"/>.
/// </returns>
private static ISessionFactory CreateSessionFactory()
{
if (sessionFactory == null)
sessionFactory = Persistence.SessionFactory.Map
(System.Web.Configuration
.WebConfigurationManager
.ConnectionStrings["Local"]
.ConnectionString
);
return sessionFactory;
}
/// <summary>
/// Open a new <see cref="NHibernate.ISession"/> from a <see cref="NHibernate.ISessionFactory"/>.
/// </summary>
/// <returns>
/// A new <see cref="NHibernate.ISession"/>.
/// </returns>
private static ISession OpenSession()
{
// check to see if we even have a session factory to get a session from
if (sessionFactory == null)
CreateSessionFactory();
// open a new session from the factory if there is no current one
return sessionFactory.OpenSession();
}
}
Я просмотрел среду выполнения, используя System.Diagnostics.Debug.WriteLine
, чтобы писать, когда что-то происходит, и она делает, как будто это делает то, что я хотел делать. То, о чем я прошу вас, сообщество, является ли это практикой хорошей или нет. Вот мое понимание.
Бесчисленные часы чтения на http://ayende.com/blog/default.aspx привели меня к переоценке большого количества способов управления сеансами.
Многое вникание в документацию nHibernate говорит мне, что мне нужно использовать ITransaction
каждый раз, когда что-либо происходит с моей базой данных.
Размещение управления в атрибуте считается недостатком, поскольку оно не соответствует указанному выше утверждению.
Выполнение ITransaction
для каждой операции не является правильным процессом, поскольку для управления (A) мои контроллеры требуется доступ к ISession
или (B) My IRepository<T>
, чтобы иметь логику ITransaction
о чем я говорил в предыдущих вопросах, не было хорошей практикой.
Размещение моего ITransaction
Менеджмента в HttpModule
добавляет ненужные служебные данные, поскольку это дает мне знание HttpContext ISession
, и это означает, что я должен сделать какую-то инъекцию в HttpRequest
(который я может использовать [Inject]
, но это не кажется мудрым)
Это привело меня к такому выводу.
- Транзакции должны начинаться с запроса
ISession
.
- Все, что происходит в одиночном запросе, инкапсулируется одним
ISession
- Когда выполняется
ITransaction
, его необходимо выполнить так, чтобы 2-й уровень кэша мог получить свои результаты.
Может ли кто-нибудь пролить свет на это? Неужели я, наконец, на правильном пути? Или я все еще пропустил это?
Ответы
Ответ 1
Я не эксперт (и у меня нет опыта работы с ninject), но я согласен с вашими 3 выводами и тем, что я делаю в своих проектах.
Еще одна вещь, которую я могу добавить, это то, что, на мой взгляд, транзакции должны контролироваться EXPLICITLY и за операцию, а не глобально (начало и начало запроса и фиксация в конце), как ваш код.
Это связано с тем, что я считаю, что вы хотите контролировать свое поведение транзакции или нет (или, возможно, даже не запускать, если нет доступа к БД) для каждой операции отдельно.
Я использую слой управления (или рабочий процесс, если вы предпочитаете), который отвечает только за это. например:
public class SomeManager : ManagersBase
{
public void DoSomething(DomainObject obj)
{
if (obj.Operation())
{
using (ITransaction tx = Session.BeginTransaction())
{
try
{
Session.Update(obj);
tx.Commit();
}
catch (MeaningfulException ex)
{
//handle
tx.Rollback();
}
}
}
}
}
надеюсь, что это поможет