Helper class featuring methods for Hibernate Session handling, allowing for reuse of Hibernate Session instances within transactions. Also provides support for exception translation.
Пример #1
0
        /// <summary>
        /// Invoked after transaction commit/rollback.
        /// </summary>
        /// <param name="status">
        /// Status according to <see cref="Spring.Transaction.Support.TransactionSynchronizationStatus"/>
        /// </param>
        /// <remarks>
        /// Can e.g. perform resource cleanup, in this case after transaction completion.
        /// <p>
        /// Note that exceptions will get propagated to the commit or rollback
        /// caller, although they will not influence the outcome of the transaction.
        /// </p>
        /// </remarks>
        public override void AfterCompletion(TransactionSynchronizationStatus status)
        {
            if (!newSession)
            {
                ISession session = sessionHolder.Session;

                // Provide correct transaction status for releasing the Session's cache locks,
                // if possible. Else, closing will release all cache locks assuming a rollback.
                ISessionImplementor sessionImplementor = session as ISessionImplementor;
                if (sessionImplementor != null)
                {
                    sessionImplementor.AfterTransactionCompletion(status == TransactionSynchronizationStatus.Committed, sessionHolder.Transaction);
                }

                if (newSession)
                {
                    SessionFactoryUtils.CloseSessionOrRegisterDeferredClose(session, sessionFactory);
                }
            }
            if (!newSession && status != TransactionSynchronizationStatus.Committed)
            {
                // Clear all pending inserts/updates/deletes in the Session.
                // Necessary for pre-bound Sessions, to avoid inconsistent state.
                sessionHolder.Session.Clear();
            }

            if (this.sessionHolder.DoesNotHoldNonDefaultSession)
            {
                sessionHolder.SynchronizedWithTransaction = false;
            }
        }
        /// <summary>
        /// Invoked by an <see cref="Spring.Objects.Factory.IObjectFactory"/>
        /// after it has injected all of an object's dependencies.
        /// </summary>
        /// <remarks>
        /// <p>
        /// This method allows the object instance to perform the kind of
        /// initialization only possible when all of it's dependencies have
        /// been injected (set), and to throw an appropriate exception in the
        /// event of misconfiguration.
        /// </p>
        /// <p>
        /// Please do consult the class level documentation for the
        /// <see cref="Spring.Objects.Factory.IObjectFactory"/> interface for a
        /// description of exactly <i>when</i> this method is invoked. In
        /// particular, it is worth noting that the
        /// <see cref="Spring.Objects.Factory.IObjectFactoryAware"/>
        /// and <see cref="Spring.Context.IApplicationContextAware"/>
        /// callbacks will have been invoked <i>prior</i> to this method being
        /// called.
        /// </p>
        /// </remarks>
        /// <exception cref="System.ArgumentException">
        /// In the event of misconfiguration (such as the failure to set a
        /// required property) or if initialization fails.
        /// </exception>
        public void AfterPropertiesSet()
        {
            if (SessionFactory == null)
            {
                throw new ArgumentException("sessionFactory is required");
            }
            if (this.entityInterceptor is string && this.objectFactory == null)
            {
                throw new ArgumentException("objectFactory is required for entityInterceptorBeanName");
            }

            // Try to derive a DbProvider given the SessionFactory.
            if (this.autodetectDbProvider && DbProvider == null)
            {
                IDbProvider sfDbProvider = SessionFactoryUtils.GetDbProvider(SessionFactory);
                if (sfDbProvider != null)
                {
                    // Use the SessionFactory's DataSource for exposing transactions to ADO.NET code.
                    if (log.IsInfoEnabled)
                    {
                        log.Info("Derived DbProvider [" + sfDbProvider.DbMetadata.ProductName +
                                 "] of Hibernate SessionFactory for HibernateTransactionManager");
                    }
                    DbProvider = sfDbProvider;
                }
                else
                {
                    log.Info("Could not auto detect DbProvider from SessionFactory configuration");
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Prepare the given IQuery object, applying cache settings and/or
        /// a transaction timeout.
        /// </summary>
        /// <param name="queryObject">The query object to prepare.</param>
        public virtual void PrepareQuery(IQuery queryObject)
        {
            if (CacheQueries)
            {
                queryObject.SetCacheable(true);
                if (QueryCacheRegion != null)
                {
                    queryObject.SetCacheRegion(QueryCacheRegion);
                }
            }

            if (FetchSize > 0)
            {
                AbstractQueryImpl queryImpl = queryObject as AbstractQueryImpl;
                if (queryImpl != null)
                {
                    queryImpl.SetFetchSize(FetchSize);
                }
                else
                {
                    log.Warn("Could not set FetchSize for IQuery.  Expected Implemention to be of type AbstractQueryImpl");
                }
            }

            if (MaxResults > 0)
            {
                queryObject.SetMaxResults(MaxResults);
            }

            SessionFactoryUtils.ApplyTransactionTimeout(queryObject, SessionFactory);
        }
Пример #4
0
        public void DbProviderTranslation()
        {
            ISessionFactory sf         = ctx["SessionFactory"] as ISessionFactory;
            IDbProvider     dbProvider = SessionFactoryUtils.GetDbProvider(sf);

            Assert.That(dbProvider.DbMetadata.ProductName, Does.Contain("Microsoft SQL Server"));
        }
Пример #5
0
 /// <summary>
 /// Invoked before transaction commit (before
 /// <see cref="Spring.Transaction.Support.ITransactionSynchronization.BeforeCompletion"/>)
 /// </summary>
 /// <param name="readOnly">
 /// If the transaction is defined as a read-only transaction.
 /// </param>
 /// <remarks>
 /// <p>
 /// Can flush transactional sessions to the database.
 /// </p>
 /// <p>
 /// Note that exceptions will get propagated to the commit caller and
 /// cause a rollback of the transaction.
 /// </p>
 /// </remarks>
 public override void BeforeCommit(bool readOnly)
 {
     if (!readOnly)
     {
         // read-write transaction -> flush the Hibernate Session
         log.Debug("Flushing Hibernate Session on transaction synchronization");
         ISession session = this.sessionHolder.Session;
         //Further check: only flush when not FlushMode.NEVER
         if (session.FlushMode != FlushMode.Never)
         {
             try
             {
                 session.Flush();
                 //TODO can throw System.ObjectDisposedException...
             }
             catch (ADOException ex)
             {
                 if (this.adoExceptionTranslator != null)
                 {
                     //TODO investigate how ADOException wraps inner exception.
                     throw this.adoExceptionTranslator.Translate(
                               "Hibernate transaction synchronization: " + ex.Message, null, ex.InnerException);
                 }
                 else
                 {
                     throw new HibernateAdoException("ADO.NET Exception", ex);
                 }
             }
             catch (HibernateException ex)
             {
                 throw SessionFactoryUtils.ConvertHibernateAccessException(ex);
             }
         }
     }
 }
Пример #6
0
        public void DbProviderTranslation()
        {
            ISessionFactory sf         = ctx["SessionFactory"] as ISessionFactory;
            IDbProvider     dbProvider = SessionFactoryUtils.GetDbProvider(sf);

            Assert.IsTrue(dbProvider.DbMetadata.ProductName.Contains("Microsoft SQL Server, provider"));
            Assert.IsTrue(dbProvider.DbMetadata.ProductName.Contains("in framework .NET"));
        }
Пример #7
0
 /// <summary>
 /// Convert the given HibernateException to an appropriate exception from the
 /// Spring's DAO Exception hierarchy.
 /// Will automatically apply a specified IAdoExceptionTranslator to a
 /// Hibernate ADOException, else rely on Hibernate's default translation.
 /// </summary>
 /// <param name="ex">The Hibernate exception that occured.</param>
 /// <returns>A corresponding DataAccessException</returns>
 protected virtual DataAccessException ConvertHibernateException(HibernateException ex)
 {
     if (ex is ADOException)
     {
         return(ConvertAdoAccessException((ADOException)ex));
     }
     return(SessionFactoryUtils.ConvertHibernateAccessException(ex));
 }
Пример #8
0
 /// <summary>
 /// Retrieve the Spring-managed Session for the current thread.
 /// </summary>
 /// <returns>Current session associated with the thread</returns>
 /// <exception cref="HibernateException">On errors retrieving thread bound session.</exception>
 public ISession CurrentSession()
 {
     try
     {
         return(SessionFactoryUtils.DoGetSession(sessionFactory, false));
     }
     catch (InvalidOperationException ex)
     {
         throw new HibernateException(ex.Message);
     }
 }
 /// <summary>
 /// Convert the given HibernateException to an appropriate exception from
 /// the Spring.Dao hierarchy. Can be overridden in subclasses.
 /// </summary>
 /// <param name="ex">The HibernateException that occured.</param>
 /// <returns>The corresponding DataAccessException instance</returns>
 protected virtual DataAccessException ConvertHibernateAccessException(HibernateException ex)
 {
     if (AdoExceptionTranslator != null && ex is ADOException)
     {
         return(ConvertAdoAccessException((ADOException)ex, AdoExceptionTranslator));
     }
     else if (ex is ADOException)
     {
         return(ConvertAdoAccessException((ADOException)ex, DefaultAdoExceptionTranslator));
     }
     return(SessionFactoryUtils.ConvertHibernateAccessException(ex));
 }
        /// <summary>
        /// Cleanup resources after transaction completion.
        /// </summary>
        /// <param name="transaction">Transaction object returned by
        /// <see cref="M:Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>.</param>
        /// <remarks>
        /// <note>
        /// This implemenation unbinds the SessionFactory and
        /// DbProvider from thread local storage and closes the
        /// ISession.
        /// </note>
        ///     <p>
        /// Called after <see cref="M:Spring.Transaction.Support.AbstractPlatformTransactionManager.DoCommit(Spring.Transaction.Support.DefaultTransactionStatus)"/>
        /// and
        /// <see cref="M:Spring.Transaction.Support.AbstractPlatformTransactionManager.DoRollback(Spring.Transaction.Support.DefaultTransactionStatus)"/>
        /// execution on any outcome.
        /// </p>
        ///     <p>
        /// Should not throw any exceptions but just issue warnings on errors.
        /// </p>
        /// </remarks>
        protected override void DoCleanupAfterCompletion(object transaction)
        {
            HibernateTransactionObject txObject = (HibernateTransactionObject)transaction;

            // Remove the session holder from the thread.
            if (txObject.NewSessionHolder)
            {
                TransactionSynchronizationManager.UnbindResource(SessionFactory);
            }
            // Remove the ADO.NET connection holder from the thread, if exposed.
            if (DbProvider != null)
            {
                TransactionSynchronizationManager.UnbindResource(DbProvider);
            }

            /*
             * try
             * {
             *  //TODO investigate isolation level settings...
             *  //IDbConnection con = txObject.SessionHolder.Session.Connection;
             *  //AdoUtils.ResetConnectionAfterTransaction(con, txObject.PreviousIsolationLevel);
             * }
             * catch (HibernateException ex)
             * {
             *  log.Info("Could not access ADO.NET IDbConnection of Hibernate Session", ex);
             * }
             */
            ISession session = txObject.SessionHolder.Session;

            if (txObject.NewSessionHolder)
            {
                if (log.IsDebugEnabled)
                {
                    log.Debug("Closing Hibernate Session [" + session + "] after transaction");
                }

                SessionFactoryUtils.CloseSessionOrRegisterDeferredClose(session, SessionFactory);
            }
            else
            {
                if (log.IsDebugEnabled)
                {
                    log.Debug("Not closing pre-bound Hibernate Session [" + session + "] after transaction");
                }
                if (txObject.SessionHolder.AssignedPreviousFlushMode)
                {
                    session.FlushMode = txObject.SessionHolder.PreviousFlushMode;
                }
            }

            txObject.SessionHolder.Clear();
        }
Пример #11
0
        public void DbProviderTransalation()
        {
            ISessionFactory sf         = ctx["SessionFactory"] as ISessionFactory;
            IDbProvider     dbProvider = SessionFactoryUtils.GetDbProvider(sf);

#if NET_2_0
            Assert.AreEqual("Microsoft SQL Server, provider V2.0.0.0 in framework .NET V2.0",
                            dbProvider.DbMetadata.ProductName);
#else
            Assert.AreEqual("Microsoft SQL Server, provider V1.0.5000.0 in framework .NET V1.1",
                            dbProvider.DbMetadata.ProductName);
#endif
        }
Пример #12
0
        public object DoInTransaction(ITransactionStatus status)
        {
            SessionHolder holder = (SessionHolder)TransactionSynchronizationManager.GetResource(sf);

            Assert.IsNotNull(holder, "Has thread session");
            Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly);
            Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive);
            tt.PropagationBehavior = TransactionPropagation.NotSupported;
            tt.Execute(new NotSupportedTxCallback(sf));

            Assert.IsTrue(holder.Session == SessionFactoryUtils.GetSession(sf, false), "Same thread session as before");
            Assert.IsFalse(TransactionSynchronizationManager.CurrentTransactionReadOnly);
            Assert.IsTrue(TransactionSynchronizationManager.ActualTransactionActive);
            return(null);
        }
        public void SessionFactoryUtilsWithGetDbProvider()
        {
            ISessionFactoryImplementor sessionFactory = A.Fake <ISessionFactoryImplementor>();

            DriverBase driver = A.Fake <DriverBase>();

            A.CallTo(() => driver.CreateCommand()).Returns(new SqlCommand());

            IConnectionProvider cp = A.Fake <IConnectionProvider>();

            A.CallTo(() => cp.Driver).Returns(driver);

            A.CallTo(() => sessionFactory.ConnectionProvider).Returns(cp);

            IDbProvider provider = SessionFactoryUtils.GetDbProvider(sessionFactory);

            Assert.AreEqual(typeof(SqlCommand), provider.DbMetadata.CommandType);
        }
Пример #14
0
        /// <summary>
        /// Prepare the given Criteria object, applying cache settings and/or
        /// a transaction timeout.
        /// </summary>
        /// <remarks>
        /// <para>Note that for NHibernate 1.2 this only works if the
        /// implementation is of the type CriteriaImpl, which should generally
        /// be the case.  The SetFetchSize method is not available on the
        /// ICriteria interface
        /// </para>
        /// <para>This is a no-op for NHibernate 1.0.x since
        /// the SetFetchSize method is not on the ICriteria interface and
        /// the implementation class is has internal access.
        /// </para>
        /// <para>To remove the method completely for Spring's NHibernate 1.0
        /// support while reusing code for NHibernate 1.2 would not be
        /// possible.  So now this ineffectual operation is left in tact for
        /// NHibernate 1.0.2 support.</para>
        /// </remarks>
        /// <param name="criteria">The criteria object to prepare</param>
        public void PrepareCriteria(ICriteria criteria)
        {
            if (CacheQueries)
            {
                criteria.SetCacheable(true);
                if (QueryCacheRegion != null)
                {
                    criteria.SetCacheRegion(QueryCacheRegion);
                }
            }



            if (FetchSize > 0)
            {
                //TODO see if we can optimize performance.
                //CriteriaImpl is internal in NH 1.0.x
                object[] args = new object[] { FetchSize };
                try
                {
                    Type t = TypeResolutionUtils.ResolveType("NHibernate.Impl.CriteriaImpl, NHibernate");
                    if (t != null)
                    {
                        t.InvokeMember("SetFetchSize", BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance
                                       | BindingFlags.InvokeMethod,
                                       null, criteria, args);
                    }
                }
                catch (TypeLoadException e)
                {
                    log.Warn("Can't set FetchSize for ICriteria", e);
                }
            }

            if (MaxResults > 0)
            {
                criteria.SetMaxResults(MaxResults);
            }

            SessionFactoryUtils.ApplyTransactionTimeout(criteria, SessionFactory);
        }
Пример #15
0
        public void SessionFactoryUtilsWithGetDbProvider()
        {
            MockRepository             mockery        = new MockRepository();
            ISessionFactoryImplementor sessionFactory = (ISessionFactoryImplementor)mockery.CreateMultiMock(typeof(ISessionFactory), typeof(ISessionFactoryImplementor));

            IDriver driver = (IDriver)mockery.DynamicMock(typeof(IDriver));

            Expect.Call(driver.CreateCommand()).Repeat.AtLeastOnce().Return(new SqlCommand());

            IConnectionProvider cp = (IConnectionProvider)mockery.DynamicMock(typeof(IConnectionProvider));

            Expect.Call(cp.Driver).Repeat.AtLeastOnce().Return(driver);

            Expect.Call(sessionFactory.ConnectionProvider).Repeat.AtLeastOnce().Return(cp);

            mockery.ReplayAll();
            IDbProvider provider = SessionFactoryUtils.GetDbProvider(sessionFactory);

            Assert.AreEqual(typeof(SqlCommand), provider.DbMetadata.CommandType);

            mockery.VerifyAll();
        }
Пример #16
0
        /// <summary>
        /// Cleanup resources after transaction completion.
        /// </summary>
        /// <param name="transaction">Transaction object returned by
        /// <see cref="M:Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>.</param>
        /// <remarks>
        /// <note>
        /// This implemenation unbinds the SessionFactory and
        /// DbProvider from thread local storage and closes the
        /// ISession.
        /// </note>
        ///     <p>
        /// Called after <see cref="M:Spring.Transaction.Support.AbstractPlatformTransactionManager.DoCommit(Spring.Transaction.Support.DefaultTransactionStatus)"/>
        /// and
        /// <see cref="M:Spring.Transaction.Support.AbstractPlatformTransactionManager.DoRollback(Spring.Transaction.Support.DefaultTransactionStatus)"/>
        /// execution on any outcome.
        /// </p>
        ///     <p>
        /// Should not throw any exceptions but just issue warnings on errors.
        /// </p>
        /// </remarks>
        protected override void DoCleanupAfterCompletion(object transaction)
        {
            HibernateTransactionObject txObject = (HibernateTransactionObject)transaction;

            // Remove the session holder from the thread.
            if (txObject.NewSessionHolder)
            {
                TransactionSynchronizationManager.UnbindResource(SessionFactory);
            }
            // Remove the ADO.NET connection holder from the thread, if exposed.
            if (DbProvider != null)
            {
                TransactionSynchronizationManager.UnbindResource(DbProvider);
            }

            ISession session = txObject.SessionHolder.Session;

            if (txObject.NewSessionHolder)
            {
                if (log.IsDebugEnabled)
                {
                    log.Debug("Closing Hibernate Session [" + session + "] after transaction");
                }
                SessionFactoryUtils.CloseSessionOrRegisterDeferredClose(session, SessionFactory);
            }
            else
            {
                if (log.IsDebugEnabled)
                {
                    log.Debug("Not closing pre-bound Hibernate Session [" + session + "] after transaction");
                }
                if (txObject.SessionHolder.AssignedPreviousFlushMode)
                {
                    session.FlushMode = txObject.SessionHolder.PreviousFlushMode;
                }
            }
            txObject.SessionHolder.Clear();
        }
Пример #17
0
 /// <summary>
 /// Converts the ADO.NET access exception to an appropriate exception from the
 /// <code>org.springframework.dao</code> hierarchy. Can be overridden in subclasses.
 /// </summary>
 /// <param name="ex">ADOException that occured, wrapping underlying ADO.NET exception.</param>
 /// <returns>
 /// the corresponding DataAccessException instance
 /// </returns>
 protected virtual DataAccessException ConvertAdoAccessException(ADOException ex)
 {
     return(SessionFactoryUtils.ConvertAdoAccessException(AdoExceptionTranslator, ex));
 }
        /// <summary>
        /// Begin a new transaction with the given transaction definition.
        /// </summary>
        /// <param name="transaction">
        /// Transaction object returned by
        /// <see cref="Spring.Transaction.Support.AbstractPlatformTransactionManager.DoGetTransaction"/>.
        /// </param>
        /// <param name="definition">
        /// <see cref="Spring.Transaction.ITransactionDefinition"/> instance, describing
        /// propagation behavior, isolation level, timeout etc.
        /// </param>
        /// <remarks>
        /// Does not have to care about applying the propagation behavior,
        /// as this has already been handled by this abstract manager.
        /// </remarks>
        /// <exception cref="Spring.Transaction.TransactionException">
        /// In the case of creation or system errors.
        /// </exception>
        protected override void DoBegin(object transaction, ITransactionDefinition definition)
        {
            TxScopeTransactionManager.PromotableTxScopeTransactionObject promotableTxScopeTransactionObject =
                ((HibernateTransactionObject)transaction).PromotableTxScopeTransactionObject;
            try
            {
                DoTxScopeBegin(promotableTxScopeTransactionObject, definition);
            }
            catch (Exception e)
            {
                throw new CannotCreateTransactionException("Transaction Scope failure on begin", e);
            }

            HibernateTransactionObject txObject = (HibernateTransactionObject)transaction;

            if (DbProvider != null && TransactionSynchronizationManager.HasResource(DbProvider) &&
                !txObject.ConnectionHolder.SynchronizedWithTransaction)
            {
                throw new IllegalTransactionStateException(
                          "Pre-bound ADO.NET Connection found - HibernateTransactionManager does not support " +
                          "running within AdoTransactionManager if told to manage the DbProvider itself. " +
                          "It is recommended to use a single HibernateTransactionManager for all transactions " +
                          "on a single DbProvider, no matter whether Hibernate or ADO.NET access.");
            }
            ISession session = null;

            try
            {
                if (txObject.SessionHolder == null || txObject.SessionHolder.SynchronizedWithTransaction)
                {
                    IInterceptor interceptor = EntityInterceptor;
                    ISession     newSession  = (interceptor != null ?
                                                SessionFactory.OpenSession(interceptor) : SessionFactory.OpenSession());

                    if (log.IsDebugEnabled)
                    {
                        log.Debug("Opened new Session [" + newSession + "] for Hibernate transaction");
                    }
                    txObject.SetSessionHolder(new SessionHolder(newSession), true);
                }
                txObject.SessionHolder.SynchronizedWithTransaction = true;
                session = txObject.SessionHolder.Session;

                IDbConnection con = session.Connection;
                //TODO isolation level mgmt
                //IsolationLevel previousIsolationLevel =

                if (definition.ReadOnly && txObject.NewSessionHolder)
                {
                    // Just set to NEVER in case of a new Session for this transaction.
                    session.FlushMode = FlushMode.Never;
                }

                if (!definition.ReadOnly && !txObject.NewSessionHolder)
                {
                    // We need AUTO or COMMIT for a non-read-only transaction.
                    FlushMode flushMode = session.FlushMode;
                    if (FlushMode.Never == flushMode)
                    {
                        session.FlushMode = FlushMode.Auto;
                        txObject.SessionHolder.PreviousFlushMode = flushMode;
                    }
                }

                // Add the Hibernate transaction to the session holder.
                // for now pass in tx options isolation level.
                ITransaction   hibernateTx = session.BeginTransaction(definition.TransactionIsolationLevel);
                IDbTransaction adoTx       = GetIDbTransaction(hibernateTx);

                // Add the Hibernate transaction to the session holder.
                txObject.SessionHolder.Transaction = hibernateTx;

                // Register transaction timeout.
                int timeout = DetermineTimeout(definition);
                if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT)
                {
                    txObject.SessionHolder.TimeoutInSeconds = timeout;
                }

                // Register the Hibernate Session's ADO.NET Connection/TX pair for the DbProvider, if set.
                if (DbProvider != null)
                {
                    //investigate passing null for tx.
                    ConnectionHolder conHolder = new ConnectionHolder(con, adoTx);
                    if (timeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT)
                    {
                        conHolder.TimeoutInMillis = definition.TransactionTimeout;
                    }
                    if (log.IsDebugEnabled)
                    {
                        log.Debug("Exposing Hibernate transaction as ADO transaction [" + con + "]");
                    }
                    TransactionSynchronizationManager.BindResource(DbProvider, conHolder);
                    txObject.ConnectionHolder = conHolder;
                }

                // Bind the session holder to the thread.
                if (txObject.NewSessionHolder)
                {
                    TransactionSynchronizationManager.BindResource(SessionFactory, txObject.SessionHolder);
                }
            }
            catch (Exception ex)
            {
                SessionFactoryUtils.CloseSession(session);
                throw new CannotCreateTransactionException("Could not open Hibernate Session for transaction", ex);
            }
        }