dotnet/efcore · error · InvalidOperationException
The entity type '{entityType}' is mapped to the stored proce
Error message
The entity type '{entityType}' is mapped to the stored procedure '{sproc}' which returns both result columns and a rows affected value. If the stored procedure returns result columns, a rows affected value isn't needed and can be safely removed. What it means
An Update/Delete stored procedure can signal optimistic-concurrency failure either by returning zero rows-affected OR by returning a result set whose columns re-select the current row values for EF to compare. Using both is redundant and ambiguous. The validator at line 925-931 throws when the sproc has result columns beyond the rows-affected result column AND any rows-affected signal is configured.
Source
Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:927
if (sproc.IsRowsAffectedReturned
|| sproc.FindRowsAffectedParameter() != null
|| sproc.FindRowsAffectedResultColumn() != null)
{
if (storeObjectIdentifier.StoreObjectType == StoreObjectType.InsertStoredProcedure)
{
throw new InvalidOperationException(
RelationalStrings.StoredProcedureRowsAffectedForInsert(
storeObjectIdentifier.DisplayName()));
}
if (originalValueProperties.Values.FirstOrDefault(p => p.IsConcurrencyToken) is { } missedConcurrencyToken)
{
logger.StoredProcedureConcurrencyTokenNotMapped(entityType, missedConcurrencyToken, storeObjectIdentifier.DisplayName());
}
if (sproc.ResultColumns.Any(c => c != sproc.FindRowsAffectedResultColumn()))
{
throw new InvalidOperationException(
RelationalStrings.StoredProcedureRowsAffectedWithResultColumns(
entityType.DisplayName(),
storeObjectIdentifier.DisplayName()));
}
}
}
/// <summary>
/// Validates a <see cref="bool" /> property with defaults.
/// </summary>
/// <param name="property">The property to validate.</param>
/// <param name="logger">The logger to use.</param>
protected virtual void ValidateBoolWithDefaults(
IProperty property,
IDiagnosticsLogger<DbLoggerCategory.Model.Validation> logger)
{
if (!property.ClrType.IsNullableType()
&& (property.ClrType.IsEnum || property.ClrType == typeof(bool))View on GitHub (pinned to dbf9771522)
Solutions
- If the sproc returns result columns, remove all rows-affected configuration (.RowsAffectedParameter/.RowsAffectedResultColumn/.ReturnsRowsAffected).
- Alternatively, remove the .ResultColumn mappings and keep only the rows-affected signal if the sproc does not re-select row data.
- Align the database stored procedure to use one strategy consistently.
Example fix
// before
modelBuilder.Entity<Order>()
.UpdateStoredProcedure(o => o
.RowsAffectedParameter("rc")
.ResultColumn(p => p.Amount, "amt")
.ResultColumn(p => p.Status, "status"));
// after - keep result columns, drop rows-affected
modelBuilder.Entity<Order>()
.UpdateStoredProcedure(o => o
.ResultColumn(p => p.Amount, "amt")
.ResultColumn(p => p.Status, "status")); Defensive patterns
Strategy: validation
Validate before calling
foreach (var et in modelBuilder.Model.GetEntityTypes())
{
foreach (var sproc in et.GetStoredProcedures())
{
bool hasRowsAffected = sproc.IsRowsAffectedReturned
|| sproc.FindRowsAffectedParameter() != null
|| sproc.FindRowsAffectedResultColumn() != null;
bool hasResultColumns = sproc.ResultColumns
.Any(c => c != sproc.FindRowsAffectedResultColumn());
if (hasRowsAffected && hasResultColumns)
{
throw new InvalidOperationException(
$"{et.Name} sproc combines rows-affected with result columns.");
}
}
} Prevention
- Pick one concurrency strategy per Update/Delete sproc: rows-affected XOR result columns.
- When migrating from rows-affected to result columns, delete the old config in the same commit.
- Document the chosen strategy in the sproc builder helper so it is applied consistently.
When it happens
Trigger: On an Update/Delete sproc: simultaneously calling `.ResultColumn(...)` for re-selected columns AND `.RowsAffectedParameter(...)` / `.RowsAffectedResultColumn(...)` / `.ReturnsRowsAffected()`.
Common situations: Copy-pasting a sproc template that returns both a row count and the full row; migrating from a rows-affected model to a result-column model but forgetting to remove the old config.
Related errors
- The entity type '{entityType}' has property '{property}' con
- The type of the etag property '{property}' on '{entityType}'
- The entity type '{entityType}' was configured to use some st
- The entity type '{entityType}' was configured to use '{sproc
- Both entity type '{entityType1}' and '{entityType2}' were co
AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06).
Data as JSON: /api/errors/cf324fc012c5c964.
Report an issue: GitHub.