How to wrap lazy loading in a transaction?

左心房为你撑大大i 提交于 2019-12-11 08:03:26

问题


I am using nhibernate and the nhibernate profile what keeps throwing this alert.

Use of implicit transactions is discouraged"

I actually wrap everything in a transaction through ninject

  public class NhibernateModule : NinjectModule
    {
        public override void Load()
        {
            Bind<ISessionFactory>().ToProvider<NhibernateSessionFactoryProvider>().InSingletonScope();
            Bind<ISession>().ToMethod(context => context.Kernel.Get<ISessionFactory>().OpenSession()).InRequestScope()
                                                                                      .OnActivation(StartTransaction)
                                                                                      .OnDeactivation(CommitTransaction);
        }

        public void CommitTransaction(ISession session)
        {

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

        }

        public void StartTransaction(ISession session)
        {
            if (!session.Transaction.IsActive)
            {
                session.BeginTransaction();
            }
        }
    }

So this should wrap everything in a transaction and it seems to work with anything that is not lazy loading.

If it is lazy loading though I get the error. What am I doing wrong.


回答1:


This is, in fact, still an implicit transaction, or relatively close to it. The injector is blissfully ignorant of everything that's happened between activation and deactivation and will happily try to commit all your changes even if the state is incorrect or corrupted.

What I see is that you're essentially trying to cheat and just have Ninject automatically start a transaction at the beginning of every request, and commit the transaction at the end of every request, hoping that it will stop NH from complaining. This is extremely bad design for several reasons:

  1. You are forcing a transaction even if the session is not used at all (i.e. opening spurious connections).
  2. There is no exception handling - if an operation fails or is rolled back, the cleanup code simply ignores that and tries to commit anyway.
  3. This will wreak havoc if you ever try to use a TransactionScope, because the scope will be completed before the NH transaction is.
  4. You lose all control over when the transactions actually happen, and give up your ability to (for example) have multiple transactions within a single request.

The NH Profiler is exactly right. This isn't appropriate use of NH transactions. In fact, if you're lazy loading, the transaction might end up being committed while you're still iterating the results - not a good situation to be in.

If you want a useful abstraction over the transactional logic and don't want to have to twiddle with ISession objects then use the Unit Of Work pattern - that's what it's designed for.

Otherwise, please code your transactions correctly, with a using clause around the operations that actually represent transactions. Yes, it's extra work, but you can't cheat your way out of it so easily.



来源:https://stackoverflow.com/questions/6245708/how-to-wrap-lazy-loading-in-a-transaction

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!