@@ -17,6 +17,9 @@ namespace Microsoft.EntityFrameworkCore.Update;
17
17
/// </remarks>
18
18
public abstract class AffectedCountModificationCommandBatch : ReaderModificationCommandBatch
19
19
{
20
+ private static readonly bool QuirkEnabled29643
21
+ = AppContext . TryGetSwitch ( "Microsoft.EntityFrameworkCore.Issue29643" , out var enabled ) && enabled ;
22
+
20
23
/// <summary>
21
24
/// Creates a new <see cref="AffectedCountModificationCommandBatch" /> instance.
22
25
/// </summary>
@@ -91,12 +94,14 @@ protected override void Consume(RelationalDataReader reader)
91
94
var parameterCounter = 0 ;
92
95
IReadOnlyModificationCommand command ;
93
96
94
- for ( commandIndex = 0 ;
95
- commandIndex < ResultSetMappings . Count ;
96
- commandIndex ++ , parameterCounter += command . StoreStoredProcedure ! . Parameters . Count )
97
+ for ( commandIndex = 0 ; commandIndex < ResultSetMappings . Count ; commandIndex ++ , parameterCounter += ParameterCount ( command ) )
97
98
{
98
99
command = ModificationCommands [ commandIndex ] ;
99
100
101
+ Check . DebugAssert (
102
+ command . ColumnModifications . All ( c => c . UseParameter ) ,
103
+ "This code assumes all column modifications involve a DbParameter (see counting above)" ) ;
104
+
100
105
if ( ! ResultSetMappings [ commandIndex ] . HasFlag ( ResultSetMapping . HasOutputParameters ) )
101
106
{
102
107
continue ;
@@ -210,12 +215,14 @@ protected override async Task ConsumeAsync(
210
215
var parameterCounter = 0 ;
211
216
IReadOnlyModificationCommand command ;
212
217
213
- for ( commandIndex = 0 ;
214
- commandIndex < ResultSetMappings . Count ;
215
- commandIndex ++ , parameterCounter += command . StoreStoredProcedure ! . Parameters . Count )
218
+ for ( commandIndex = 0 ; commandIndex < ResultSetMappings . Count ; commandIndex ++ , parameterCounter += ParameterCount ( command ) )
216
219
{
217
220
command = ModificationCommands [ commandIndex ] ;
218
221
222
+ Check . DebugAssert (
223
+ command . ColumnModifications . All ( c => c . UseParameter ) ,
224
+ "This code assumes all column modifications involve a DbParameter (see counting above)" ) ;
225
+
219
226
if ( ! ResultSetMappings [ commandIndex ] . HasFlag ( ResultSetMapping . HasOutputParameters ) )
220
227
{
221
228
continue ;
@@ -448,6 +455,40 @@ await ThrowAggregateUpdateConcurrencyExceptionAsync(
448
455
return commandIndex - 1 ;
449
456
}
450
457
458
+ private static int ParameterCount ( IReadOnlyModificationCommand command )
459
+ {
460
+ if ( QuirkEnabled29643 )
461
+ {
462
+ return command . StoreStoredProcedure ! . Parameters . Count ;
463
+ }
464
+
465
+ // As a shortcut, if the command uses a stored procedure, return the number of parameters directly from it.
466
+ if ( command . StoreStoredProcedure is { } storedProcedure )
467
+ {
468
+ return storedProcedure . Parameters . Count ;
469
+ }
470
+
471
+ // Otherwise we need to count the total parameters used by all column modifications
472
+ var parameterCount = 0 ;
473
+
474
+ for ( var i = 0 ; i < command . ColumnModifications . Count ; i ++ )
475
+ {
476
+ var columnModification = command . ColumnModifications [ i ] ;
477
+
478
+ if ( columnModification . UseCurrentValueParameter )
479
+ {
480
+ parameterCount ++ ;
481
+ }
482
+
483
+ if ( columnModification . UseOriginalValueParameter )
484
+ {
485
+ parameterCount ++ ;
486
+ }
487
+ }
488
+
489
+ return parameterCount ;
490
+ }
491
+
451
492
private IReadOnlyList < IUpdateEntry > AggregateEntries ( int endIndex , int commandCount )
452
493
{
453
494
var entries = new List < IUpdateEntry > ( ) ;
0 commit comments