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}', however the store-generated properties {properties} are not mapped to any output parameter or result column.

What it means

Every store-generated property (identity, computed, ValueGenerated.OnAdd/OnUpdate) must have a way for EF to read the generated value back after an Insert or Update — either an output parameter or a result column. The validator at line 847-854 collects the leftover storeGeneratedProperties after processing all parameters and result columns and throws if any remain, because EF would otherwise have no way to refresh those values.

Source

Thrown at src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs:849

        {
            if (resultColumn.PropertyName == null)
            {
                continue;
            }

            properties.Remove(resultColumn.PropertyName);

            if (!storeGeneratedProperties.Remove(resultColumn.PropertyName))
            {
                throw new InvalidOperationException(
                    RelationalStrings.StoredProcedureResultColumnParameterConflict(
                        entityType.DisplayName(), resultColumn.PropertyName, storeObjectIdentifier.DisplayName()));
            }
        }

        if (storeGeneratedProperties.Count > 0)
        {
            throw new InvalidOperationException(
                RelationalStrings.StoredProcedureGeneratedPropertiesNotMapped(
                    entityType.DisplayName(),
                    storeObjectIdentifier.DisplayName(),
                    storeGeneratedProperties.Values.Format()));
        }

        if (properties.Count > 0)
        {
            foreach (var property in properties.Values.ToList())
            {
                switch (storeObjectIdentifier.StoreObjectType)
                {
                    case StoreObjectType.InsertStoredProcedure:
                        if ((property.ValueGenerated & ValueGenerated.OnAdd) == 0
                            && property.GetBeforeSaveBehavior() != PropertySaveBehavior.Save)
                        {
                            properties.Remove(property.Name);
                        }

View on GitHub (pinned to dbf9771522)

Solutions

  1. Add an .OutputParameter(p => p.<GeneratedProp>, "<param>") or .ResultColumn(p => p.<GeneratedProp>, "<col>") to the sproc mapping for each listed property.
  2. Update the database stored procedure to actually return those values via an OUTPUT/SELECT.
  3. If the property is not actually generated by the database, remove the ValueGenerated/HasComputedColumnSql configuration so it is treated as client-set.

Example fix

// before
modelBuilder.Entity<Order>()
    .Property(p => p.CreatedAt).ValueGeneratedOnAdd();
modelBuilder.Entity<Order>()
    .InsertStoredProcedure(o => o
        .Parameter(p => p.Amount, "amt")); // CreatedAt not read back

// after
modelBuilder.Entity<Order>()
    .InsertStoredProcedure(o => o
        .Parameter(p => p.Amount, "amt")
        .ResultColumn(p => p.CreatedAt, "created_at"));
Defensive patterns

Strategy: validation

Validate before calling

foreach (var et in modelBuilder.Model.GetEntityTypes())
{
    var generated = et.GetProperties()
        .Where(p => p.ValueGenerated != ValueGenerated.Never).ToList();
    foreach (var sproc in et.GetStoredProcedures())
    {
        if (sproc.StoreObjectType is not (StoreObjectType.InsertStoredProcedure
                                          or StoreObjectType.UpdateStoredProcedure)) continue;
        var mapped = new HashSet<string>(
            sproc.Parameters.Where(p => p.Direction != ParameterDirection.Input && p.PropertyName != null)
                           .Select(p => p.PropertyName));
        mapped.UnionWith(sproc.ResultColumns.Where(r => r.PropertyName != null).Select(r => r.PropertyName));
        var missing = generated.Where(p => !mapped.Contains(p.Name)).ToList();
        if (missing.Count > 0)
            throw new InvalidOperationException(
                $"{et.Name}: generated props unmapped in sproc: {string.Join(", ", missing.Select(p => p.Name))}");
    }
}

Prevention

When it happens

Trigger: Marking a property `.ValueGeneratedOnAdd()` / `.HasComputedColumnSql(...)` on an entity whose Insert/Update sproc is configured but does not expose a corresponding `.OutputParameter(...)` or `.ResultColumn(...)` for that property.

Common situations: Adding a new computed column to an entity that already uses sproc mapping and forgetting to extend the sproc config; sproc was authored before an identity column was added.

Related errors


AI-assisted analysis of dotnet/efcore@dbf9771522 (2026-08-06). Data as JSON: /api/errors/1df951b7eb90550f. Report an issue: GitHub.