Exemple #1
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);
            }
        }
Exemple #2
0
        /// <summary>
        /// Stops tracking the transaction that was rolled back.
        /// </summary>
        /// <param name="transaction">The transaction that was rolled back.</param>
        /// <param name="interceptionContext">Contextual information associated with the call.</param>
        /// <seealso cref="IDbTransactionInterceptor.RolledBack" />
        public override void RolledBack(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);
            TransactionContext.Entry(transactionRow).State = EntityState.Detached;
        }
Exemple #3
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);
            }
        }
Exemple #4
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) ||
                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;
                    }
                }
            }
        }