/// <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; } } } } }
/// <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> /// 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); }
private void PruneTransactionHistory(TransactionRow transaction) { this.MarkTransactionForPruning(transaction); try { this.PruneTransactionHistory(false, false); } catch (DataException ex) { } }
private void PruneTransactionHistory(TransactionRow transaction) { MarkTransactionForPruning(transaction); try { PruneTransactionHistory(force: false, useExecutionStrategy: false); } catch (DataException) { } }
/// <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); } }
/// <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); } }
/// <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); } }
private void PruneTransactionRows(TransactionRow transaction) { MarkTransactionForPruning(transaction); PruneTransactionRows(force: false); }
/// <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; } } } }