Beispiel #1
0
        /// <summary>
        /// Stores the tracking information for the new transaction to the database in the same transaction.
        /// </summary>
        /// <param name="connection">The connection that began the transaction.</param>
        /// <param name="interceptionContext">Contextual information associated with the call.</param>
        /// <seealso cref="M:System.Data.Entity.Infrastructure.Interception.IDbConnectionInterceptor.BeganTransaction(System.Data.Common.DbConnection,System.Data.Entity.Infrastructure.Interception.BeginTransactionInterceptionContext)" />
        public override void BeganTransaction(
            DbConnection connection,
            BeginTransactionInterceptionContext interceptionContext)
        {
            if (this.TransactionContext == null || !this.MatchesParentContext(connection, (DbInterceptionContext)interceptionContext) || interceptionContext.Result == null)
            {
                return;
            }
            Guid          transactionId = Guid.NewGuid();
            bool          flag1         = false;
            bool          flag2         = false;
            ObjectContext objectContext = ((IObjectContextAdapter)this.TransactionContext).ObjectContext;

            ((EntityConnection)objectContext.Connection).UseStoreTransaction(interceptionContext.Result);
            while (!flag1)
            {
                TransactionRow entity = new TransactionRow()
                {
                    Id           = transactionId,
                    CreationTime = DateTime.Now
                };
                this._transactions.Add(interceptionContext.Result, entity);
                this.TransactionContext.Transactions.Add(entity);
                try
                {
                    objectContext.SaveChangesInternal(SaveOptions.AcceptAllChangesAfterSave, true);
                    flag1 = true;
                }
                catch (UpdateException ex1)
                {
                    this._transactions.Remove(interceptionContext.Result);
                    this.TransactionContext.Entry <TransactionRow>(entity).State = EntityState.Detached;
                    if (flag2)
                    {
                        throw;
                    }
                    else
                    {
                        try
                        {
                            if (this.TransactionContext.Transactions.AsNoTracking <TransactionRow>().WithExecutionStrategy <TransactionRow>((IDbExecutionStrategy) new DefaultExecutionStrategy()).FirstOrDefault <TransactionRow>((Expression <Func <TransactionRow, bool> >)(t => t.Id == transactionId)) != null)
                            {
                                transactionId = Guid.NewGuid();
                            }
                            else
                            {
                                throw;
                            }
                        }
                        catch (EntityCommandExecutionException ex2)
                        {
                            this.TransactionContext.Database.Initialize(true);
                            flag2 = true;
                        }
                    }
                }
            }
        }
Beispiel #2
0
        /// <summary>
        /// Adds the specified transaction to the list of transactions that can be removed from the database
        /// </summary>
        /// <param name="transaction">The transaction to be removed from the database.</param>
        protected virtual void MarkTransactionForPruning(TransactionRow transaction)
        {
            Check.NotNull(transaction, "transaction");

            if (!_rowsToDelete.Contains(transaction))
            {
                _rowsToDelete.Add(transaction);
            }
        }
Beispiel #3
0
 /// <summary>
 /// Adds the specified transaction to the list of transactions that can be removed from the database
 /// </summary>
 /// <param name="transaction">The transaction to be removed from the database.</param>
 protected virtual void MarkTransactionForPruning(TransactionRow transaction)
 {
     Check.NotNull <TransactionRow>(transaction, nameof(transaction));
     if (this._rowsToDelete.Contains(transaction))
     {
         return;
     }
     this._rowsToDelete.Add(transaction);
 }
Beispiel #4
0
 private void PruneTransactionHistory(TransactionRow transaction)
 {
     this.MarkTransactionForPruning(transaction);
     try
     {
         this.PruneTransactionHistory(false, false);
     }
     catch (DataException ex)
     {
     }
 }
Beispiel #5
0
        private void PruneTransactionHistory(TransactionRow transaction)
        {
            MarkTransactionForPruning(transaction);

            try
            {
                PruneTransactionHistory(force: false, useExecutionStrategy: false);
            }
            catch (DataException)
            {
            }
        }
Beispiel #6
0
        /// <summary>
        /// If there was an exception thrown checks the database for this transaction and rethrows it if not found.
        /// Otherwise marks the commit as succeeded and queues the transaction information to be deleted.
        /// </summary>
        /// <param name="transaction">The transaction that was commited.</param>
        /// <param name="interceptionContext">Contextual information associated with the call.</param>
        /// <seealso cref="IDbTransactionInterceptor.Committed" />
        public override void Committed(DbTransaction transaction, DbTransactionInterceptionContext interceptionContext)
        {
            TransactionRow transactionRow;

            if (TransactionContext == null ||
                (interceptionContext.Connection != null && !MatchesParentContext(interceptionContext.Connection, interceptionContext)) ||
                !Transactions.TryGetValue(transaction, out transactionRow))
            {
                return;
            }

            Transactions.Remove(transaction);
            if (interceptionContext.Exception != null)
            {
                TransactionRow existingTransactionRow = null;
                var            suspendedState         = DbExecutionStrategy.Suspended;
                try
                {
                    DbExecutionStrategy.Suspended = false;
                    var executionStrategy = GetExecutionStrategy()
                                            ?? DbProviderServices.GetExecutionStrategy(interceptionContext.Connection);
                    existingTransactionRow = TransactionContext.Transactions
                                             .AsNoTracking()
                                             .WithExecutionStrategy(executionStrategy)
                                             .SingleOrDefault(t => t.Id == transactionRow.Id);
                }
                catch (EntityCommandExecutionException)
                {
                    // Error during verification, assume commit failed
                }
                finally
                {
                    DbExecutionStrategy.Suspended = suspendedState;
                }

                if (existingTransactionRow != null)
                {
                    // The transaction id is still in the database, so the commit succeeded
                    interceptionContext.Exception = null;

                    PruneTransactionHistory(transactionRow);
                }
                else
                {
                    TransactionContext.Entry(transactionRow).State = EntityState.Detached;
                }
            }
            else
            {
                PruneTransactionHistory(transactionRow);
            }
        }
Beispiel #7
0
        /// <summary>
        /// If there was an exception thrown checks the database for this transaction and rethrows it if not found.
        /// Otherwise marks the commit as succeeded and queues the transaction information to be deleted.
        /// </summary>
        /// <param name="transaction">The transaction that was commited.</param>
        /// <param name="interceptionContext">Contextual information associated with the call.</param>
        /// <seealso cref="IDbTransactionInterceptor.Committed" />
        public override void Committed(DbTransaction transaction, DbTransactionInterceptionContext interceptionContext)
        {
            TransactionRow transactionRow;

            if (TransactionContext == null ||
                (interceptionContext.Connection != null && !MatchesParentContext(interceptionContext.Connection, interceptionContext)) ||
                !_transactions.TryGetValue(transaction, out transactionRow))
            {
                return;
            }

            _transactions.Remove(transaction);
            if (interceptionContext.Exception != null)
            {
                TransactionRow existingTransactionRow = null;
                try
                {
                    existingTransactionRow = TransactionContext.Transactions
                                             .AsNoTracking()
                                             .WithExecutionStrategy(new DefaultExecutionStrategy())
                                             .SingleOrDefault(t => t.Id == transactionRow.Id);
                }
                catch (EntityCommandExecutionException)
                {
                    // Transaction table doesn't exist
                }

                if (existingTransactionRow != null)
                {
                    // The transaction id is still in the database, so the commit succeeded
                    interceptionContext.Exception = null;

                    PruneTransactionHistory(transactionRow);
                }
                else
                {
                    TransactionContext.Entry(transactionRow).State = EntityState.Detached;
                }
            }
            else
            {
                PruneTransactionHistory(transactionRow);
            }
        }
Beispiel #8
0
        /// <summary>
        /// If there was an exception thrown checks the database for this transaction and rethrows it if not found.
        /// Otherwise marks the commit as succeeded and queues the transaction information to be deleted.
        /// </summary>
        /// <param name="transaction">The transaction that was commited.</param>
        /// <param name="interceptionContext">Contextual information associated with the call.</param>
        /// <seealso cref="M:System.Data.Entity.Infrastructure.Interception.IDbTransactionInterceptor.Committed(System.Data.Common.DbTransaction,System.Data.Entity.Infrastructure.Interception.DbTransactionInterceptionContext)" />
        public override void Committed(
            DbTransaction transaction,
            DbTransactionInterceptionContext interceptionContext)
        {
            TransactionRow transactionRow;

            if (this.TransactionContext == null || interceptionContext.Connection != null && !this.MatchesParentContext(interceptionContext.Connection, (DbInterceptionContext)interceptionContext) || !this._transactions.TryGetValue(transaction, out transactionRow))
            {
                return;
            }
            this._transactions.Remove(transaction);
            if (interceptionContext.Exception != null)
            {
                TransactionRow transactionRow1 = (TransactionRow)null;
                try
                {
                    transactionRow1 = this.TransactionContext.Transactions.AsNoTracking <TransactionRow>().WithExecutionStrategy <TransactionRow>((IDbExecutionStrategy) new DefaultExecutionStrategy()).SingleOrDefault <TransactionRow>((Expression <Func <TransactionRow, bool> >)(t => t.Id == transactionRow.Id));
                }
                catch (EntityCommandExecutionException ex)
                {
                }
                if (transactionRow1 != null)
                {
                    interceptionContext.Exception = (Exception)null;
                    this.PruneTransactionHistory(transactionRow);
                }
                else
                {
                    this.TransactionContext.Entry <TransactionRow>(transactionRow).State = EntityState.Detached;
                }
            }
            else
            {
                this.PruneTransactionHistory(transactionRow);
            }
        }
Beispiel #9
0
 private void PruneTransactionRows(TransactionRow transaction)
 {
     MarkTransactionForPruning(transaction);
     PruneTransactionRows(force: false);
 }
Beispiel #10
0
        /// <summary>
        /// Stores the tracking information for the new transaction to the database in the same transaction.
        /// </summary>
        /// <param name="connection">The connection that began the transaction.</param>
        /// <param name="interceptionContext">Contextual information associated with the call.</param>
        /// <seealso cref="IDbConnectionInterceptor.BeganTransaction" />
        public override void BeganTransaction(DbConnection connection, BeginTransactionInterceptionContext interceptionContext)
        {
            if (TransactionContext == null ||
                !MatchesParentContext(connection, interceptionContext))
            {
                return;
            }

            var transactionId         = Guid.NewGuid();
            var savedSuccesfully      = false;
            var reinitializedDatabase = false;

            while (!savedSuccesfully)
            {
                Debug.Assert(!_transactions.ContainsKey(interceptionContext.Result), "The transaction has already been registered");
                var transactionRow = new TransactionRow {
                    Id = transactionId, CreationTime = DateTime.Now
                };
                _transactions.Add(interceptionContext.Result, transactionRow);
                TransactionContext.Transactions.Add(transactionRow);

                var objectContext = ((IObjectContextAdapter)TransactionContext).ObjectContext;
                ((EntityConnection)objectContext.Connection).UseStoreTransaction(interceptionContext.Result);
                try
                {
                    objectContext.SaveChanges(SaveOptions.DetectChangesBeforeSave, executeInExistingTransaction: true);
                    savedSuccesfully = true;
                }
                catch (UpdateException)
                {
                    _transactions.Remove(interceptionContext.Result);
                    TransactionContext.Transactions.Remove(transactionRow);

                    if (reinitializedDatabase)
                    {
                        throw;
                    }

                    try
                    {
                        var existingTransaction =
                            TransactionContext.Transactions
                            .AsNoTracking()
                            .WithExecutionStrategy(new DefaultExecutionStrategy())
                            .FirstOrDefault(t => t.Id == transactionId);

                        if (existingTransaction != null)
                        {
                            transactionId = Guid.NewGuid();
                            Debug.Assert(false, "Duplicate GUID! this should never happen");
                        }
                    }
                    catch (EntityCommandExecutionException)
                    {
                        // The necessary tables are not present.
                        // This can happen if the database was deleted after TransactionContext has been initialized
                        TransactionContext.Database.Initialize(force: true);

                        reinitializedDatabase = true;
                    }

                    interceptionContext.Result.Rollback();
                    interceptionContext.Result = connection.BeginTransaction(interceptionContext.IsolationLevel);
                }
            }
        }
        private void PruneTransactionHistory(TransactionRow transaction)
        {
            MarkTransactionForPruning(transaction);

            try
            {
                PruneTransactionHistory(force: false, useExecutionStrategy: false);
            }
            catch (DataException)
            {
            }
        }
        /// <summary>
        /// Adds the specified transaction to the list of transactions that can be removed from the database
        /// </summary>
        /// <param name="transaction">The transaction to be removed from the database.</param>
        protected virtual void MarkTransactionForPruning(TransactionRow transaction)
        {
            Check.NotNull(transaction, "transaction");

            if (!_rowsToDelete.Contains(transaction))
            {
                _rowsToDelete.Add(transaction);
            }
        }
        /// <summary>
        /// Stores the tracking information for the new transaction to the database in the same transaction.
        /// </summary>
        /// <param name="connection">The connection that began the transaction.</param>
        /// <param name="interceptionContext">Contextual information associated with the call.</param>
        /// <seealso cref="IDbConnectionInterceptor.BeganTransaction" />
        public override void BeganTransaction(DbConnection connection, BeginTransactionInterceptionContext interceptionContext)
        {
            if (TransactionContext == null
                || !MatchesParentContext(connection, interceptionContext)
                || interceptionContext.Result == null)
            {
                return;
            }

            var transactionId = Guid.NewGuid();
            var savedSuccesfully = false;
            var reinitializedDatabase = false;
            var objectContext = ((IObjectContextAdapter)TransactionContext).ObjectContext;
            ((EntityConnection)objectContext.Connection).UseStoreTransaction(interceptionContext.Result);
            while (!savedSuccesfully)
            {
                Debug.Assert(!_transactions.ContainsKey(interceptionContext.Result), "The transaction has already been registered");
                var transactionRow = new TransactionRow { Id = transactionId, CreationTime = DateTime.Now };
                _transactions.Add(interceptionContext.Result, transactionRow);

                TransactionContext.Transactions.Add(transactionRow);
                try
                {
                    objectContext.SaveChangesInternal(SaveOptions.AcceptAllChangesAfterSave, executeInExistingTransaction: true);
                    savedSuccesfully = true;
                }
                catch (UpdateException)
                {
                    _transactions.Remove(interceptionContext.Result);
                    TransactionContext.Entry(transactionRow).State = EntityState.Detached;

                    if (reinitializedDatabase)
                    {
                        throw;
                    }

                    try
                    {
                        var existingTransaction =
                            TransactionContext.Transactions
                                .AsNoTracking()
                                .WithExecutionStrategy(new DefaultExecutionStrategy())
                                .FirstOrDefault(t => t.Id == transactionId);

                        if (existingTransaction != null)
                        {
                            transactionId = Guid.NewGuid();
                            Debug.Assert(false, "Duplicate GUID! this should never happen");
                        }
                        else
                        {
                            // Unknown exception cause
                            throw;
                        }
                    }
                    catch (EntityCommandExecutionException)
                    {
                        // The necessary tables are not present.
                        // This can happen if the database was deleted after TransactionContext has been initialized
                        TransactionContext.Database.Initialize(force: true);

                        reinitializedDatabase = true;
                    }
                }
            }
        }