/// <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"); } } }
/// <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); }
public void DbProviderTranslation() { ISessionFactory sf = ctx["SessionFactory"] as ISessionFactory; IDbProvider dbProvider = SessionFactoryUtils.GetDbProvider(sf); Assert.That(dbProvider.DbMetadata.ProductName, Does.Contain("Microsoft SQL Server")); }
/// <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); } } } }
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")); }
/// <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)); }
/// <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(); }
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 }
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); }
/// <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); }
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(); }
/// <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(); }
/// <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); } }