Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stop wrapping OperationCancellationException with DbUpdateException #25628

Merged
merged 1 commit into from
Aug 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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