Requires the object factory to be known, to be able to resolve the object
+ /// name to an interceptor instance on session creation. Typically used for
+ /// prototype interceptors, i.e. a new interceptor instance per session.
+ ///
+ ///
Can also be used for shared interceptor instances, but it is recommended
+ /// to set the interceptor reference directly in such a scenario.
+ ///
+ ///
+ public string EntityInterceptorObjectName
+ {
+ set
+ {
+ entityInterceptor = value;
+ }
+ }
+
+ ///
+ /// Gets or sets the ADO.NET exception translator for this transaction manager.
+ ///
+ ///
+ /// Applied to ADO.NET Exceptions (wrapped by Hibernate's ADOException)
+ ///
+ /// The ADO exception translator.
+ public IAdoExceptionTranslator AdoExceptionTranslator
+ {
+ get { return adoExceptionTranslator; }
+ set { adoExceptionTranslator = value; }
+ }
+
+ ///
+ /// Gets the default IAdoException translator, lazily creating it if nece
+ ///
+ /// The default IAdoException translator.
+ public IAdoExceptionTranslator DefaultAdoExceptionTranslator
+ {
+ get
+ {
+ lock (this)
+ {
+ if (defaultExceptionTranslator == null)
+ {
+ if (dbProvider != null)
+ {
+ defaultExceptionTranslator = new ErrorCodeExceptionTranslator(dbProvider);
+ }
+ else
+ {
+ defaultExceptionTranslator = SessionFactoryUtils.NewAdoExceptionTranslator(SessionFactory);
+ }
+ }
+ return defaultExceptionTranslator;
+ }
+ }
+ }
+
+ ///
+ /// Gets or sets the SessionFactory that this instance should manage transactions for.
+ ///
+ /// The session factory.
+ public ISessionFactory SessionFactory
+ {
+ get { return sessionFactory; }
+ set { sessionFactory = value; }
+ }
+
+
+ ///
+ /// Gets the resource factory that this transaction manager operates on,
+ /// For the HibenratePlatformTransactionManager this the SessionFactory
+ ///
+ /// The SessionFactory.
+ public object ResourceFactory
+ {
+ get { return sessionFactory; }
+ }
+
+ ///
+ /// Set whether to autodetect a ADO.NET connection used by the Hibernate SessionFactory,
+ /// if set via LocalSessionFactoryObject's DbProvider. Default is "true".
+ ///
+ ///
+ /// true if [autodetect data source]; otherwise, false.
+ ///
+ ///
+ ///
Can be turned off to deliberately ignore an available IDbProvider,
+ /// to not expose Hibernate transactions as ADO.NET transactions for that IDbProvider.
+ ///
+ ///
+ public bool AutodetectDbProvider
+ {
+ set { autodetectDbProvider = value; }
+ }
+
+ #endregion
+
+ #region Methods
+
+ #endregion
+
+
+ ///
+ /// The object factory just needs to be known for resolving entity interceptor
+ /// It does not need to be set for any other mode of operation.
+ ///
+ ///
+ /// Owning
+ /// (may not be ). The object can immediately
+ /// call methods on the factory.
+ ///
+ public IObjectFactory ObjectFactory
+ {
+ set
+ {
+ objectFactory = value;
+ }
+ }
+
+ ///
+ /// Return the current transaction object.
+ ///
+ /// The current transaction object.
+ ///
+ /// If transaction support is not available.
+ ///
+ ///
+ /// In the case of lookup or system errors.
+ ///
+ protected override object DoGetTransaction()
+ {
+
+
+ HibernateTransactionObject txObject = new HibernateTransactionObject();
+ txObject.SavepointAllowed = NestedTransactionsAllowed;
+ if (TransactionSynchronizationManager.HasResource(SessionFactory))
+ {
+ SessionHolder sessionHolder =
+ (SessionHolder)TransactionSynchronizationManager.GetResource(SessionFactory);
+ if (log.IsDebugEnabled)
+ {
+ log.Debug("Found thread-bound Session [" + sessionHolder.Session +
+ "] for Hibernate transaction");
+ }
+ txObject.SetSessionHolder(sessionHolder, false);
+ if (DbProvider != null)
+ {
+ ConnectionHolder conHolder = (ConnectionHolder)
+ TransactionSynchronizationManager.GetResource(DbProvider);
+ txObject.ConnectionHolder = conHolder;
+ }
+ }
+ txObject.PromotableTxScopeTransactionObject = new TxScopeTransactionManager.PromotableTxScopeTransactionObject();
+
+ return txObject;
+ }
+
+ ///
+ /// Check if the given transaction object indicates an existing,
+ /// i.e. already begun, transaction.
+ ///
+ ///
+ /// Transaction object returned by
+ /// .
+ ///
+ /// True if there is an existing transaction.
+ ///
+ /// In the case of system errors.
+ ///
+ protected override bool IsExistingTransaction(object transaction)
+ {
+ return
+ ((HibernateTransactionObject)transaction).PromotableTxScopeTransactionObject.TxScopeAdapter.
+ IsExistingTransaction;
+ //return ((HibernateTransactionObject) transaction).HasTransaction();
+ }
+
+ ///
+ /// Begin a new transaction with the given transaction definition.
+ ///
+ ///
+ /// Transaction object returned by
+ /// .
+ ///
+ ///
+ /// instance, describing
+ /// propagation behavior, isolation level, timeout etc.
+ ///
+ ///
+ /// Does not have to care about applying the propagation behavior,
+ /// as this has already been handled by this abstract manager.
+ ///
+ ///
+ /// In the case of creation or system errors.
+ ///
+ 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);
+ }
+
+
+ }
+
+ private void DoTxScopeBegin(TxScopeTransactionManager.PromotableTxScopeTransactionObject txObject,
+ Spring.Transaction.ITransactionDefinition definition)
+ {
+
+ TransactionScopeOption txScopeOption = CreateTransactionScopeOptions(definition);
+ TransactionOptions txOptions = CreateTransactionOptions(definition);
+ txObject.TxScopeAdapter.CreateTransactionScope(txScopeOption, txOptions, definition.EnterpriseServicesInteropOption);
+
+ }
+
+ private static TransactionScopeOption CreateTransactionScopeOptions(ITransactionDefinition definition)
+ {
+ TransactionScopeOption txScopeOption;
+ if (definition.PropagationBehavior == TransactionPropagation.Required)
+ {
+ txScopeOption = TransactionScopeOption.Required;
+ }
+ else if (definition.PropagationBehavior == TransactionPropagation.RequiresNew)
+ {
+ txScopeOption = TransactionScopeOption.RequiresNew;
+ }
+ else if (definition.PropagationBehavior == TransactionPropagation.NotSupported)
+ {
+ txScopeOption = TransactionScopeOption.Suppress;
+ }
+ else
+ {
+ throw new Spring.Transaction.TransactionSystemException("Transaction Propagation Behavior" +
+ definition.PropagationBehavior +
+ " not supported by TransactionScope. Use Required or RequiredNew");
+ }
+ return txScopeOption;
+ }
+
+
+ private static TransactionOptions CreateTransactionOptions(ITransactionDefinition definition)
+ {
+ TransactionOptions txOptions = new TransactionOptions();
+ switch (definition.TransactionIsolationLevel)
+ {
+ case System.Data.IsolationLevel.Chaos:
+ txOptions.IsolationLevel = System.Transactions.IsolationLevel.Chaos;
+ break;
+ case System.Data.IsolationLevel.ReadCommitted:
+ txOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
+ break;
+ case System.Data.IsolationLevel.ReadUncommitted:
+ txOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadUncommitted;
+ break;
+ case System.Data.IsolationLevel.RepeatableRead:
+ txOptions.IsolationLevel = System.Transactions.IsolationLevel.RepeatableRead;
+ break;
+ case System.Data.IsolationLevel.Serializable:
+ txOptions.IsolationLevel = System.Transactions.IsolationLevel.Serializable;
+ break;
+ case System.Data.IsolationLevel.Snapshot:
+ txOptions.IsolationLevel = System.Transactions.IsolationLevel.Snapshot;
+ break;
+ case System.Data.IsolationLevel.Unspecified:
+ txOptions.IsolationLevel = System.Transactions.IsolationLevel.Unspecified;
+ break;
+ }
+
+ if (definition.TransactionTimeout != DefaultTransactionDefinition.TIMEOUT_DEFAULT)
+ {
+ txOptions.Timeout = new TimeSpan(0, 0, definition.TransactionTimeout);
+ }
+ return txOptions;
+ }
+
+
+
+ ///
+ /// Suspend the resources of the current transaction.
+ ///
+ ///
+ /// Transaction object returned by
+ /// .
+ ///
+ ///
+ /// An object that holds suspended resources (will be kept unexamined for passing it into
+ /// .)
+ ///
+ ///
+ /// Transaction synchronization will already have been suspended.
+ ///
+ ///
+ /// If suspending is not supported by the transaction manager implementation.
+ ///
+ ///
+ /// in case of system errors.
+ ///
+ protected override object DoSuspend(object transaction)
+ {
+ HibernateTransactionObject txObject = (HibernateTransactionObject)transaction;
+ txObject.SetSessionHolder(null, false);
+ SessionHolder sessionHolder =
+ (SessionHolder)TransactionSynchronizationManager.UnbindResource(SessionFactory);
+ ConnectionHolder connectionHolder = null;
+ if (DbProvider != null)
+ {
+ connectionHolder = (ConnectionHolder)TransactionSynchronizationManager.UnbindResource(DbProvider);
+ }
+ return new SuspendedResourcesHolder(sessionHolder, connectionHolder);
+
+ }
+
+ ///
+ /// Resume the resources of the current transaction.
+ ///
+ ///
+ /// Transaction object returned by
+ /// .
+ ///
+ ///
+ /// The object that holds suspended resources as returned by
+ /// .
+ ///
+ ///
+ /// Transaction synchronization will be resumed afterwards.
+ ///
+ ///
+ /// If suspending is not supported by the transaction manager implementation.
+ ///
+ ///
+ /// In the case of system errors.
+ ///
+ protected override void DoResume(object transaction, object suspendedResources)
+ {
+ SuspendedResourcesHolder resourcesHolder = (SuspendedResourcesHolder)suspendedResources;
+ if (TransactionSynchronizationManager.HasResource(SessionFactory))
+ {
+ // From non-transactional code running in active transaction synchronization
+ // -> can be safely removed, will be closed on transaction completion.
+ TransactionSynchronizationManager.UnbindResource(SessionFactory);
+ }
+ TransactionSynchronizationManager.BindResource(SessionFactory, resourcesHolder.SessionHolder);
+ if (DbProvider != null)
+ {
+ TransactionSynchronizationManager.BindResource(DbProvider, resourcesHolder.ConnectionHolder);
+ }
+ }
+
+ ///
+ /// Perform an actual commit on the given transaction.
+ ///
+ /// The status representation of the transaction.
+ ///
+ ///
+ /// An implementation does not need to check the rollback-only flag.
+ ///
+ ///
+ ///
+ /// In the case of system errors.
+ ///
+ protected override void DoCommit(DefaultTransactionStatus status)
+ {
+ HibernateTransactionObject txObject = (HibernateTransactionObject)status.Transaction;
+ if (status.Debug)
+ {
+ log.Debug("Committing Hibernate transaction on Session [" +
+ txObject.SessionHolder.Session + "]");
+ }
+ try
+ {
+ txObject.SessionHolder.Transaction.Commit();
+ }
+ // Note, unfortunate collision of namespaces/classname for NHibernate.TransactionException
+ // and Spring.Data.NHibernate requires this wierd construct.
+ catch (Exception ex)
+ {
+ Type nhibTxExceptiontype = TypeResolutionUtils.ResolveType("NHibernate.TransactionException, NHibernate");
+ if (ex.GetType().Equals(nhibTxExceptiontype))
+ {
+ // assumably from commit call to the underlying ADO.NET connection
+ throw new TransactionSystemException("Could not commit Hibernate transaction", ex);
+ }
+ HibernateException hibEx = ex as HibernateException;
+ if (hibEx != null)
+ {
+ // assumably failed to flush changes to database
+ throw ConvertHibernateAccessException(hibEx);
+ }
+ throw;
+ }
+ finally
+ {
+ DoTxScopeCommit(status);
+ }
+
+
+
+ }
+
+ protected void DoTxScopeCommit(DefaultTransactionStatus status)
+ {
+ TxScopeTransactionManager.PromotableTxScopeTransactionObject txObject =
+ ((HibernateTransactionObject)status.Transaction).PromotableTxScopeTransactionObject;
+ try
+ {
+ txObject.TxScopeAdapter.Complete();
+ txObject.TxScopeAdapter.Dispose();
+ }
+ catch (TransactionAbortedException ex)
+ {
+ throw new UnexpectedRollbackException("Transaction unexpectedly rolled back (maybe due to a timeout)", ex);
+ }
+ catch (TransactionInDoubtException ex)
+ {
+ throw new HeuristicCompletionException(TransactionOutcomeState.Unknown, ex);
+ }
+ catch (Exception ex)
+ {
+ throw new TransactionSystemException("Failure on Transaction Scope Commit", ex);
+ }
+ }
+
+ ///
+ /// Perform an actual rollback on the given transaction.
+ ///
+ /// The status representation of the transaction.
+ ///
+ /// An implementation does not need to check the new transaction flag.
+ ///
+ ///
+ /// In the case of system errors.
+ ///
+ protected override void DoRollback(DefaultTransactionStatus status)
+ {
+ HibernateTransactionObject txObject = (HibernateTransactionObject)status.Transaction;
+ if (status.Debug)
+ {
+ log.Debug("Rolling back Hibernate transaction on Session [" +
+ txObject.SessionHolder.Session + "]");
+ }
+ try
+ {
+ txObject.SessionHolder.Transaction.Rollback();
+ }
+ catch (HibernateTransactionException ex)
+ {
+ throw new TransactionSystemException("Could not roll back Hibernate transaction", ex);
+ }
+ catch (HibernateException ex)
+ {
+ // Shouldn't really happen, as a rollback doesn't cause a flush.
+ throw ConvertHibernateAccessException(ex);
+ }
+ finally
+ {
+ if (!txObject.NewSessionHolder)
+ {
+ // Clear all pending inserts/updates/deletes in the Session.
+ // Necessary for pre-bound Sessions, to avoid inconsistent state.
+ txObject.SessionHolder.Session.Clear();
+ }
+ DoTxScopeRollback(status);
+ }
+ }
+
+ protected void DoTxScopeRollback(DefaultTransactionStatus status)
+ {
+ TxScopeTransactionManager.PromotableTxScopeTransactionObject txObject =
+ ((HibernateTransactionObject)status.Transaction).PromotableTxScopeTransactionObject;
+
+ try
+ {
+
+ txObject.TxScopeAdapter.Dispose();
+ }
+ catch (Exception e)
+ {
+ throw new Spring.Transaction.TransactionSystemException("Failure on Transaction Scope rollback.", e);
+ }
+ }
+
+ ///
+ /// Set the given transaction rollback-only. Only called on rollback
+ /// if the current transaction takes part in an existing one.
+ ///
+ /// The status representation of the transaction.
+ ///
+ /// In the case of system errors.
+ ///
+ protected override void DoSetRollbackOnly(DefaultTransactionStatus status)
+ {
+ HibernateTransactionObject txObject = (HibernateTransactionObject)status.Transaction;
+ if (status.Debug)
+ {
+ log.Debug("Setting Hibernate transaction on Session [" +
+ txObject.SessionHolder.Session + "] rollback-only");
+ }
+ txObject.SetRollbackOnly();
+
+ DoTxScopeSetRollbackOnly(status);
+ }
+
+ protected void DoTxScopeSetRollbackOnly(DefaultTransactionStatus status)
+ {
+ if (status.Debug)
+ {
+ log.Debug("Setting transaction rollback-only");
+ }
+ try
+ {
+ System.Transactions.Transaction.Current.Rollback();
+ }
+ catch (Exception ex)
+ {
+ throw new TransactionSystemException("Failure on System.Transactions.Transaction.Current.Rollback", ex);
+ }
+ }
+
+
+ ///
+ /// Gets the ADO.NET IDbTransaction object from the NHibernate ITransaction object.
+ ///
+ /// The hibernate transaction.
+ /// The ADO.NET transaction. Null if could not get the transaction. Warning
+ /// messages will be logged in that case.
+ protected IDbTransaction GetIDbTransaction(ITransaction hibernateTx)
+ {
+ AdoTransaction hibernateAdoTx = hibernateTx as AdoTransaction;
+
+ IDbTransaction adoTransaction = null;
+ if (hibernateAdoTx != null)
+ {
+ try
+ {
+ FieldInfo fi = hibernateAdoTx.GetType().GetField("trans", BindingFlags.Instance | BindingFlags.NonPublic);
+ adoTransaction = fi.GetValue(hibernateAdoTx) as IDbTransaction;
+ }
+ catch (Exception e)
+ {
+ log.Warn("Could not extract IDbTransaction from Hibernate AdoTransaction using field name trans.", e);
+ }
+ }
+ else
+ {
+ log.Warn("Hibernate ITransaction not of expected type AdoTransaction. Could not extract IDbTransaction from Hibernate AdoTransaction.");
+ }
+ return adoTransaction;
+ }
+
+ ///
+ /// Convert the given HibernateException to an appropriate exception from
+ /// the Spring.Dao hierarchy. Can be overridden in subclasses.
+ ///
+ /// The HibernateException that occured.
+ /// The corresponding DataAccessException instance
+ 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);
+ }
+
+ ///
+ /// Convert the given ADOException to an appropriate exception from the
+ /// the Spring.Dao hierarchy. Can be overridden in subclasses.
+ ///
+ /// The ADOException that occured, wrapping the underlying
+ /// ADO.NET thrown exception.
+ /// The translator to convert hibernate ADOExceptions.
+ ///
+ /// The corresponding DataAccessException instance
+ ///
+ protected virtual DataAccessException ConvertAdoAccessException(ADOException ex, IAdoExceptionTranslator translator)
+ {
+ return translator.Translate("Hibernate flusing: " + ex.Message, null, ex.InnerException);
+ }
+
+ ///
+ /// Cleanup resources after transaction completion.
+ ///
+ /// Transaction object returned by
+ /// .
+ ///
+ ///
+ /// This implemenation unbinds the SessionFactory and
+ /// DbProvider from thread local storage and closes the
+ /// ISession.
+ ///
+ ///
+ /// Called after
+ /// and
+ ///
+ /// execution on any outcome.
+ ///
+ ///
+ /// Should not throw any exceptions but just issue warnings on errors.
+ ///
+ ///
+ 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();
+
+
+ }
+
+ private class HibernateTransactionObject : AdoTransactionObjectSupport
+ {
+
+ private SessionHolder sessionHolder;
+
+ private bool newSessionHolder;
+
+ private TxScopeTransactionManager.PromotableTxScopeTransactionObject promotableTxScopeTransactionObject;
+
+
+ public void SetSessionHolder(SessionHolder sessionHolder, bool newSessionHolder)
+ {
+ this.sessionHolder = sessionHolder;
+ this.newSessionHolder = newSessionHolder;
+ }
+
+ public TxScopeTransactionManager.PromotableTxScopeTransactionObject PromotableTxScopeTransactionObject
+ {
+ get { return promotableTxScopeTransactionObject; }
+ set { this.promotableTxScopeTransactionObject = value; }
+ }
+
+ public SessionHolder SessionHolder
+ {
+ get
+ {
+ return sessionHolder;
+ }
+ }
+
+ public bool NewSessionHolder
+ {
+ get
+ {
+ return newSessionHolder;
+ }
+ }
+
+ public bool HasTransaction()
+ {
+ return (this.sessionHolder != null && this.sessionHolder.Transaction != null);
+ }
+
+ public void SetRollbackOnly()
+ {
+ SessionHolder.RollbackOnly = true;
+ if (ConnectionHolder != null)
+ {
+ ConnectionHolder.RollbackOnly = true;
+ }
+ }
+
+ ///
+ /// Return whether the transaction is internally marked as rollback-only.
+ ///
+ ///
+ /// True of the transaction is marked as rollback-only.
+ public override bool RollbackOnly
+ {
+ get
+ {
+ return SessionHolder.RollbackOnly ||
+ (ConnectionHolder != null && ConnectionHolder.RollbackOnly);
+ }
+ }
+ }
+
+ private class SuspendedResourcesHolder
+ {
+
+ private readonly SessionHolder sessionHolder;
+
+ private readonly ConnectionHolder connectionHolder;
+
+ public SuspendedResourcesHolder(SessionHolder sessionHolder, ConnectionHolder conHolder)
+ {
+ this.sessionHolder = sessionHolder;
+ this.connectionHolder = conHolder;
+ }
+
+ public SessionHolder SessionHolder
+ {
+ get
+ {
+ return sessionHolder;
+ }
+
+ }
+
+ public ConnectionHolder ConnectionHolder
+ {
+ get
+ {
+ return connectionHolder;
+ }
+
+ }
+ }
+
+ ///
+ /// Invoked by an
+ /// after it has injected all of an object's dependencies.
+ ///
+ ///
+ ///
+ /// 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.
+ ///
+ ///
+ /// Please do consult the class level documentation for the
+ /// interface for a
+ /// description of exactly when this method is invoked. In
+ /// particular, it is worth noting that the
+ ///
+ /// and
+ /// callbacks will have been invoked prior to this method being
+ /// called.
+ ///