private int?PreExecution(IRelationalConnection connection) { int?errorNumber = null; var testConnection = (TestSqlServerConnection)connection; testConnection.ExecutionCount++; if (testConnection.ExecutionFailures.Count > 0) { var fail = testConnection.ExecutionFailures.Dequeue(); if (fail.HasValue) { if (fail.Value) { testConnection.DbConnection.Close(); throw SqlExceptionFactory.CreateSqlException(testConnection.ErrorNumber); } errorNumber = testConnection.ErrorNumber; } } return(errorNumber); }
public override void Commit() { if (_testConnection.CommitFailures.Count > 0) { var fail = _testConnection.CommitFailures.Dequeue(); if (fail.HasValue) { if (fail.Value) { this.GetDbTransaction().Rollback(); } else { this.GetDbTransaction().Commit(); } _testConnection.DbConnection.Close(); throw SqlExceptionFactory.CreateSqlException(_testConnection.ErrorNumber, _testConnection.ConnectionId); } } base.Commit(); }
public override async Task CommitAsync(CancellationToken cancellationToken = default) { if (_testConnection.CommitFailures.Count > 0) { var fail = _testConnection.CommitFailures.Dequeue(); if (fail.HasValue) { if (fail.Value) { await this.GetDbTransaction().RollbackAsync(cancellationToken); } else { await this.GetDbTransaction().CommitAsync(cancellationToken); } await _testConnection.DbConnection.CloseAsync(); throw SqlExceptionFactory.CreateSqlException(_testConnection.ErrorNumber, _testConnection.ConnectionId); } } await base.CommitAsync(cancellationToken); }
public async Task Retries_SaveChanges_on_execution_failure_with_two_contexts( bool realFailure, bool openConnection, bool async) { CleanContext(); using (var context = CreateContext()) { using var auditContext = new AuditContext(); var connection = (TestSqlServerConnection)context.GetService <ISqlServerConnection>(); connection.ExecutionFailures.Enqueue(new bool?[] { null, realFailure }); Assert.Equal(ConnectionState.Closed, context.Database.GetDbConnection().State); if (openConnection) { if (async) { await context.Database.OpenConnectionAsync(); } else { context.Database.OpenConnection(); } Assert.Equal(ConnectionState.Open, context.Database.GetDbConnection().State); } context.Products.Add(new Product()); context.Products.Add(new Product()); var throwTransientError = true; if (async) { await new TestSqlServerRetryingExecutionStrategy(context).ExecuteInTransactionAsync( (MainContext: context, AuditContext: auditContext), async(c, ct) => { var result = await c.MainContext.SaveChangesAsync(false, ct); c.AuditContext.ChangeTracker.Clear(); c.AuditContext.Database.SetDbConnection(c.MainContext.Database.GetDbConnection()); var currentTransaction = c.AuditContext.Database.CurrentTransaction; if (throwTransientError) { Assert.Null(currentTransaction); } else { Assert.NotNull(currentTransaction); } await c.AuditContext.Database.UseTransactionAsync( c.MainContext.Database.CurrentTransaction !.GetDbTransaction(), ct); Assert.NotSame(currentTransaction, c.AuditContext.Database.CurrentTransaction); await c.AuditContext.Audits.AddAsync(new Audit(), ct); await c.AuditContext.SaveChangesAsync(ct); if (throwTransientError) { throwTransientError = false; throw SqlExceptionFactory.CreateSqlException(10928); } return(result); }, (c, _) => { Assert.True(false); return(Task.FromResult(false)); }); context.ChangeTracker.AcceptAllChanges(); } else { new TestSqlServerRetryingExecutionStrategy(context).ExecuteInTransaction( (MainContext: context, AuditContext: auditContext), c => { var result = c.MainContext.SaveChanges(false); c.AuditContext.ChangeTracker.Clear(); c.AuditContext.Database.SetDbConnection(c.MainContext.Database.GetDbConnection()); var currentTransaction = c.AuditContext.Database.CurrentTransaction; if (throwTransientError) { Assert.Null(currentTransaction); } else { Assert.NotNull(currentTransaction); } c.AuditContext.Database.UseTransaction(c.MainContext.Database.CurrentTransaction !.GetDbTransaction()); Assert.NotSame(currentTransaction, c.AuditContext.Database.CurrentTransaction); c.AuditContext.Audits.Add(new Audit()); c.AuditContext.SaveChanges(); if (throwTransientError) { throwTransientError = false; throw SqlExceptionFactory.CreateSqlException(10928); } return(result); }, c => { Assert.True(false); return(false); }); context.ChangeTracker.AcceptAllChanges(); } Assert.Equal(openConnection ? 2 : 3, connection.OpenCount); Assert.Equal(6, connection.ExecutionCount); Assert.Equal( openConnection ? ConnectionState.Open : ConnectionState.Closed, context.Database.GetDbConnection().State); if (openConnection) { if (async) { await context.Database.CloseConnectionAsync(); } else { context.Database.CloseConnection(); } } Assert.Equal(ConnectionState.Closed, context.Database.GetDbConnection().State); } using (var context = CreateContext()) { Assert.Equal(2, context.Products.Count()); } }