Skip to content

Commit

Permalink
Stop wrapping OperationCancellationException with DbUpdateException (#…
Browse files Browse the repository at this point in the history
  • Loading branch information
roji authored Aug 20, 2021
1 parent 85b0670 commit 23b33a1
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 34 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ protected override void Consume(RelationalDataReader reader)
"Expected " + expectedResultSetCount + " result sets, got " + actualResultSetCount);
#endif
}
catch (Exception ex) when (!(ex is DbUpdateException))
catch (Exception ex) when (ex is not DbUpdateException and not OperationCanceledException)
{
throw new DbUpdateException(
RelationalStrings.UpdateStoreException,
Expand Down Expand Up @@ -150,7 +150,7 @@ protected override async Task ConsumeAsync(
"Expected " + expectedResultSetCount + " result sets, got " + actualResultSetCount);
#endif
}
catch (Exception ex) when (!(ex is DbUpdateException))
catch (Exception ex) when (ex is not DbUpdateException and not OperationCanceledException)
{
throw new DbUpdateException(
RelationalStrings.UpdateStoreException,
Expand Down
12 changes: 2 additions & 10 deletions src/EFCore.Relational/Update/ReaderModificationCommandBatch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -252,11 +252,7 @@ public override void Execute(IRelationalConnection connection)
Dependencies.Logger, CommandSource.SaveChanges));
Consume(dataReader);
}
catch (DbUpdateException)
{
throw;
}
catch (Exception ex)
catch (Exception ex) when (ex is not DbUpdateException and not OperationCanceledException)
{
throw new DbUpdateException(
RelationalStrings.UpdateStoreException,
Expand Down Expand Up @@ -293,11 +289,7 @@ public override async Task ExecuteAsync(
cancellationToken).ConfigureAwait(false);
await ConsumeAsync(dataReader, cancellationToken).ConfigureAwait(false);
}
catch (DbUpdateException)
{
throw;
}
catch (Exception ex)
catch (Exception ex) when (ex is not DbUpdateException and not OperationCanceledException)
{
throw new DbUpdateException(
RelationalStrings.UpdateStoreException,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Data.Common;

namespace Microsoft.EntityFrameworkCore.TestUtilities.FakeProvider
{
public class FakeDbException : DbException
{
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -261,8 +261,10 @@ public async Task Exception_not_thrown_for_more_than_one_row_returned_for_single
Assert.Equal(42, entry[entry.EntityType.FindProperty("Id")]);
}

[ConditionalFact]
public async Task Exception_thrown_if_rows_returned_for_command_without_store_generated_values_is_not_1()
[ConditionalTheory]
[InlineData(false)]
[InlineData(true)]
public async Task Exception_thrown_if_rows_returned_for_command_without_store_generated_values_is_not_1(bool async)
{
var entry = CreateEntry(EntityState.Added);

Expand All @@ -276,14 +278,17 @@ public async Task Exception_thrown_if_rows_returned_for_command_without_store_ge
var batch = new ModificationCommandBatchFake();
batch.AddCommand(command);

Assert.Equal(
RelationalStrings.UpdateConcurrencyException(1, 42),
(await Assert.ThrowsAsync<DbUpdateConcurrencyException>(
async () => await batch.ExecuteAsync(connection))).Message);
var exception = async
? await Assert.ThrowsAsync<DbUpdateConcurrencyException>(() => batch.ExecuteAsync(connection))
: Assert.Throws<DbUpdateConcurrencyException>(() => batch.Execute(connection));

Assert.Equal(RelationalStrings.UpdateConcurrencyException(1, 42), exception.Message);
}

[ConditionalFact]
public async Task Exception_thrown_if_no_rows_returned_for_command_with_store_generated_values()
[ConditionalTheory]
[InlineData(false)]
[InlineData(true)]
public async Task Exception_thrown_if_no_rows_returned_for_command_with_store_generated_values(bool async)
{
var entry = CreateEntry(EntityState.Added, generateKeyValues: true);
entry.SetTemporaryValue(entry.EntityType.FindPrimaryKey().Properties[0], -1);
Expand All @@ -297,10 +302,65 @@ public async Task Exception_thrown_if_no_rows_returned_for_command_with_store_ge
var batch = new ModificationCommandBatchFake();
batch.AddCommand(command);

Assert.Equal(
RelationalStrings.UpdateConcurrencyException(1, 0),
(await Assert.ThrowsAsync<DbUpdateConcurrencyException>(
async () => await batch.ExecuteAsync(connection))).Message);
var exception = async
? await Assert.ThrowsAsync<DbUpdateConcurrencyException>(() => batch.ExecuteAsync(connection))
: Assert.Throws<DbUpdateConcurrencyException>(() => batch.Execute(connection));

Assert.Equal(RelationalStrings.UpdateConcurrencyException(1, 0), exception.Message);
}

[ConditionalTheory]
[InlineData(false)]
[InlineData(true)]
public async Task DbException_is_wrapped_with_DbUpdateException(bool async)
{
var entry = CreateEntry(EntityState.Added, generateKeyValues: true);

var command = CreateModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null);
command.AddEntry(entry, true);

var originalException = new FakeDbException();

var connection = CreateConnection(
new FakeCommandExecutor(
executeReaderAsync: (c, b, ct) => throw originalException,
executeReader: (c, b) => throw originalException));

var batch = new ModificationCommandBatchFake();
batch.AddCommand(command);

var actualException = async
? await Assert.ThrowsAsync<DbUpdateException>(() => batch.ExecuteAsync(connection))
: Assert.Throws<DbUpdateException>(() => batch.Execute(connection));

Assert.Same(originalException, actualException.InnerException);
}

[ConditionalTheory]
[InlineData(false)]
[InlineData(true)]
public async Task OperationCanceledException_is_not_wrapped_with_DbUpdateException(bool async)
{
var entry = CreateEntry(EntityState.Added, generateKeyValues: true);

var command = CreateModificationCommand("T1", null, new ParameterNameGenerator().GenerateNext, true, null);
command.AddEntry(entry, true);

var originalException = new OperationCanceledException();

var connection = CreateConnection(
new FakeCommandExecutor(
executeReaderAsync: (c, b, ct) => throw originalException,
executeReader: (c, b) => throw originalException));

var batch = new ModificationCommandBatchFake();
batch.AddCommand(command);

var actualException = async
? await Assert.ThrowsAsync<OperationCanceledException>(() => batch.ExecuteAsync(connection))
: Assert.Throws<OperationCanceledException>(() => batch.Execute(connection));

Assert.Same(originalException, actualException);
}

[ConditionalFact]
Expand Down Expand Up @@ -605,21 +665,18 @@ private class FakeDbContext : DbContext

private const string ConnectionString = "Fake Connection String";

private static FakeRelationalConnection CreateConnection(FakeCommandExecutor executor)
=> CreateConnection(
CreateOptions(
new FakeRelationalOptionsExtension().WithConnection(
new FakeDbConnection(ConnectionString, executor))));

private static FakeRelationalConnection CreateConnection(DbDataReader dbDataReader)
{
var fakeDbConnection = new FakeDbConnection(
ConnectionString,
=> CreateConnection(
new FakeCommandExecutor(
executeReaderAsync: (c, b, ct) => Task.FromResult(dbDataReader),
executeReader: (c, b) => dbDataReader));

var optionsExtension = new FakeRelationalOptionsExtension().WithConnection(fakeDbConnection);

var options = CreateOptions(optionsExtension);

return CreateConnection(options);
}

private static FakeRelationalConnection CreateConnection(IDbContextOptions options = null)
=> new(options ?? CreateOptions());

Expand Down

0 comments on commit 23b33a1

Please sign in to comment.