Skip to content

Commit

Permalink
Sproc fixes
Browse files Browse the repository at this point in the history
* Don't attempt to propagate rows affected result columns

Fixes dotnet#28803
  • Loading branch information
roji committed Aug 31, 2022
1 parent 5525fce commit 8ea1d60
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 10 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,7 @@ protected override void Consume(RelationalDataReader reader)

if (resultSetMapping.HasFlag(ResultSetMapping.HasResultRow))
{
if (onResultSet == false)
{
Check.DebugFail("Missing a result set");
}
Check.DebugAssert(onResultSet != false, "Missing a result set");

var lastHandledCommandIndex = command.RequiresResultPropagation
? ConsumeResultSetWithPropagation(commandIndex, reader)
Expand All @@ -75,7 +72,9 @@ protected override void Consume(RelationalDataReader reader)
}
}

Debug.Assert(onResultSet != true, "Unexpected result set found at end");
// TODO: This should be a warning, not an assertion; it gets tripped when a user executes a sproc which returns something
// (e.g. rows affected) but forgets to configure that in metadata
// Check.DebugAssert(onResultSet != true, "Unexpected result set found at end");

if (hasOutputParameters)
{
Expand Down Expand Up @@ -166,10 +165,7 @@ protected override async Task ConsumeAsync(

if (resultSetMapping.HasFlag(ResultSetMapping.HasResultRow))
{
if (onResultSet == false)
{
Check.DebugFail("Missing a result set");
}
Check.DebugAssert(onResultSet != false, "Missing a result set");

var lastHandledCommandIndex = command.RequiresResultPropagation
? await ConsumeResultSetWithPropagationAsync(commandIndex, reader, cancellationToken).ConfigureAwait(false)
Expand All @@ -190,7 +186,9 @@ protected override async Task ConsumeAsync(
}
}

Debug.Assert(onResultSet != true, "Unexpected result set found at end");
// TODO: This should be a warning, not an assertion; it gets tripped when a user executes a sproc which returns something
// (e.g. rows affected) but forgets to configure that in metadata
// Check.DebugAssert(onResultSet != true, "Unexpected result set found at end");

if (hasOutputParameters)
{
Expand Down
5 changes: 5 additions & 0 deletions src/EFCore.Relational/Update/ModificationCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -866,6 +866,11 @@ public virtual void PropagateResults(RelationalDataReader relationalReader)
break;

case IStoreStoredProcedureResultColumn resultColumn:
if (ReferenceEquals(RowsAffectedColumn, resultColumn))
{
continue;
}

// For stored procedure result sets, we need to get the column ordering from metadata.
readerIndex = resultColumn.Position;
#if DEBUG
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ public DbSet<EntityWithAdditionalProperty> WithTwoResultColumns
public DbSet<EntityWithAdditionalProperty> WithOutputParameterAndResultColumn
=> Set<EntityWithAdditionalProperty>(nameof(WithOutputParameterAndResultColumn));

public DbSet<EntityWithAdditionalProperty> WithOutputParameterAndRowsAffectedResultColumn
=> Set<EntityWithAdditionalProperty>(nameof(WithOutputParameterAndRowsAffectedResultColumn));

public DbSet<EntityWithTwoAdditionalProperties> WithOutputParameterAndResultColumnAndResultValue
=> Set<EntityWithTwoAdditionalProperties>(nameof(WithOutputParameterAndResultColumnAndResultValue));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,21 @@ protected override void OnModelCreating(ModelBuilder modelBuilder, DbContext con
.HasResultColumn(w => w.AdditionalProperty));
});

modelBuilder.SharedTypeEntity<EntityWithAdditionalProperty>(
nameof(StoredProcedureUpdateContext.WithOutputParameterAndRowsAffectedResultColumn),
b =>
{
b.Property(w => w.AdditionalProperty).HasComputedColumnSql("8");

b.UpdateUsingStoredProcedure(
nameof(StoredProcedureUpdateContext.WithOutputParameterAndRowsAffectedResultColumn) + "_Update",
spb => spb
.HasParameter(w => w.Id)
.HasParameter(w => w.Name)
.HasParameter(w => w.AdditionalProperty, pb => pb.IsOutput())
.HasRowsAffectedResultColumn());
});

modelBuilder.SharedTypeEntity<EntityWithAdditionalProperty>(nameof(StoredProcedureUpdateContext.WithTwoOutputParameters))
.UpdateUsingStoredProcedure(
nameof(StoredProcedureUpdateContext.WithTwoOutputParameters) + "_Update", spb => spb
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,31 @@ public virtual async Task Update_partial(bool async)
}
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Update_with_output_parameter_and_rows_affected_result_column(bool async)
{
await using var context = CreateContext();

var entity = new EntityWithAdditionalProperty { Name = "Foo" };
context.WithOutputParameterAndRowsAffectedResultColumn.Add(entity);
await context.SaveChangesAsync();

entity.Name = "Updated";

ClearLog();

await SaveChanges(context, async);

using (Fixture.TestSqlLoggerFactory.SuspendRecordingEvents())
{
var actual = await context.WithOutputParameterAndRowsAffectedResultColumn.SingleAsync(w => w.Id == entity.Id);

Assert.Equal("Updated", actual.Name);
Assert.Equal(8, actual.AdditionalProperty);
}
}

[ConditionalTheory]
[MemberData(nameof(IsAsyncData))]
public virtual async Task Delete(bool async)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,19 @@ public override async Task Update_partial(bool async)
EXEC [WithTwoOutputParameters_Update] @p0, @p1, @p2;");
}

public override async Task Update_with_output_parameter_and_rows_affected_result_column(bool async)
{
await base.Update_with_output_parameter_and_rows_affected_result_column(async);

AssertSql(
@"@p0='1'
@p1='Updated' (Size = 4000)
@p2=NULL (Nullable = false) (Direction = Output) (DbType = Int32)
SET NOCOUNT ON;
EXEC [WithOutputParameterAndRowsAffectedResultColumn_Update] @p0, @p1, @p2 OUTPUT;");
}

public override async Task Delete(bool async)
{
await base.Delete(async);
Expand Down Expand Up @@ -384,6 +397,7 @@ public override void CleanData()
TRUNCATE TABLE [WithOriginalAndCurrentValueOnNonConcurrencyToken];
TRUNCATE TABLE [WithOutputParameter];
TRUNCATE TABLE [WithOutputParameterAndResultColumn];
TRUNCATE TABLE [WithOutputParameterAndRowsAffectedResultColumn];
TRUNCATE TABLE [WithOutputParameterAndResultColumnAndResultValue];
TRUNCATE TABLE [WithResultColumn];
TRUNCATE TABLE [WithTwoResultColumns];
Expand Down Expand Up @@ -458,10 +472,19 @@ AS BEGIN
GO
CREATE PROCEDURE WithOutputParameterAndRowsAffectedResultColumn_Update(@Id int, @Name varchar(max), @AdditionalProperty int OUT)
AS BEGIN
UPDATE [WithOutputParameterAndRowsAffectedResultColumn] SET [Name] = @Name, @AdditionalProperty = [AdditionalProperty] WHERE [Id] = @Id;
SELECT @@ROWCOUNT;
END;
GO
CREATE PROCEDURE WithTwoOutputParameters_Update(@Id int, @Name varchar(max), @AdditionalProperty int)
AS UPDATE [WithTwoOutputParameters] SET [Name] = @Name, [AdditionalProperty] = @AdditionalProperty WHERE [Id] = @id;
GO
CREATE PROCEDURE WithRowsAffectedParameter_Update(@Id int, @Name varchar(max), @RowsAffected int OUT)
AS BEGIN
UPDATE [WithRowsAffectedParameter] SET [Name] = @Name WHERE [Id] = @Id;
Expand Down

0 comments on commit 8ea1d60

Please sign in to comment.