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 properties {properties} are not mapped to any parameter or result column.

What it means

After filtering out properties that are non-saveable, non-generated, or only relevant for original-value concurrency tokens, any remaining properties must be mapped to a parameter or result column of the stored procedure. The validator at line 899-906 throws for the surviving set, meaning these are concrete properties EF expects to persist or read but the sproc mapping does not cover them.

Source

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

                        {
                            properties.Remove(property.Name);
                        }

                        break;
                }
            }

            foreach (var property in properties.Keys.ToList())
            {
                if (!originalValueProperties.ContainsKey(property))
                {
                    properties.Remove(property);
                }
            }

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

        if (sproc.IsRowsAffectedReturned
            || sproc.FindRowsAffectedParameter() != null
            || sproc.FindRowsAffectedResultColumn() != null)
        {
            if (storeObjectIdentifier.StoreObjectType == StoreObjectType.InsertStoredProcedure)
            {
                throw new InvalidOperationException(
                    RelationalStrings.StoredProcedureRowsAffectedForInsert(
                        storeObjectIdentifier.DisplayName()));
            }

View on GitHub (pinned to dbf9771522)

Solutions

  1. Add .Parameter(p => p.<MissingProp>, "<param>") for each listed property in the matching Insert/Update/Delete sproc.
  2. Update the database stored procedure signature to accept the new parameter.
  3. If the property should not be persisted by this sproc, configure its BeforeSaveBehavior/AfterSaveBehavior to Ignore so the validator filters it out.

Example fix

// before
modelBuilder.Entity<Order>()
    .UpdateStoredProcedure(o => o
        .Parameter(p => p.Amount, "amt")); // Status missing

// after
modelBuilder.Entity<Order>()
    .UpdateStoredProcedure(o => o
        .Parameter(p => p.Amount, "amt")
        .Parameter(p => p.Status, "status"));
Defensive patterns

Strategy: validation

Validate before calling

foreach (var et in modelBuilder.Model.GetEntityTypes())
{
    foreach (var sproc in et.GetStoredProcedures())
    {
        var mappedParams = sproc.Parameters.Where(p => p.PropertyName != null).Select(p => p.PropertyName).ToHashSet();
        var mappedCols = sproc.ResultColumns.Where(r => r.PropertyName != null).Select(r => r.PropertyName).ToHashSet();
        foreach (var prop in et.GetProperties())
        {
            bool saveable = sproc.StoreObjectType switch
            {
                StoreObjectType.InsertStoredProcedure =>
                    prop.GetBeforeSaveBehavior() == PropertySaveBehavior.Save
                    || (prop.ValueGenerated & ValueGenerated.OnAdd) != 0,
                StoreObjectType.UpdateStoredProcedure =>
                    prop.IsPrimaryKey() || prop.IsConcurrencyToken
                    || (prop.ValueGenerated & ValueGenerated.OnUpdate) != 0
                    || prop.GetAfterSaveBehavior() == PropertySaveBehavior.Save,
                StoreObjectType.DeleteStoredProcedure => prop.IsPrimaryKey() || prop.IsConcurrencyToken,
                _ => false
            };
            if (saveable && !mappedParams.Contains(prop.Name) && !mappedCols.Contains(prop.Name))
            {
                // potential gap — investigate and add .Parameter(...) mapping
            }
        }
    }
}

Prevention

When it happens

Trigger: Mapping an entity to an Insert/Update/Delete sproc but omitting `.Parameter(...)` for one or more writable properties. The filtering at lines 860-888 only removes properties that are genuinely irrelevant (e.g. not saveable in that direction); anything left is required.

Common situations: Adding a new required column to an entity and not updating the sproc config; switching an entity to sproc mapping and missing a property in the manual parameter list (sprocs do not auto-map columns the way tables do).

Related errors


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