dotnet/efcore · error · InvalidOperationException

The property ' . ' is mapped to a result column of the…

Error message

The property '{entityType}.{property}' is mapped to a result column of the stored procedure '{sproc}', but it is not configured as store-generated.

What it means

Thrown in the result-column switch for Insert and Update sprocs when the bound property is not in storeGeneratedProperties (RelationalModelValidator.cs:678-685). storeGeneratedProperties is computed at lines 633-640 as properties with ValueGenerated.OnAdd (insert) or ValueGenerated.OnUpdate (update). A result column implies the DB produces the value, so the property must be marked store-generated.

Solutions

  1. Mark the property store-generated to match the sproc type: .ValueGeneratedOnAdd() for insert result columns, .ValueGeneratedOnUpdate() (or .ValueGeneratedOnAddOrUpdate()) for update.
  2. If the property isn't actually DB-generated, remove the HasResultColumn binding and pass it as an input parameter instead.
  3. For computed columns use .ValueGeneratedOnAddOrUpdate() so they appear in both store-generated sets.

Example fix

// before
modelBuilder.Entity<Customer>()
    .InsertUsingStoredProcedure("dbo.CustomerInsert", sp =>
    {
        sp.HasParameter(c => c.Name);
        sp.HasResultColumn(c => c.CreatedAt); // not marked store-generated
    });

// after
modelBuilder.Entity<Customer>(b =>
{
    b.Property(c => c.CreatedAt).ValueGeneratedOnAdd();
    b.InsertUsingStoredProcedure("dbo.CustomerInsert", sp =>
    {
        sp.HasParameter(c => c.Name);
        sp.HasResultColumn(c => c.CreatedAt);
    });
});
Defensive patterns

Strategy: validation

Validate before calling

foreach (var et in modelBuilder.Model.GetEntityTypes())
{
    var insert = et.GetInsertStoredProcedure();
    var update = et.GetUpdateStoredProcedure();
    if (insert is not null)
    {
        var gen = et.GetProperties().Where(p => p.ValueGenerated.HasFlag(ValueGenerated.OnAdd)).Select(p => p.Name).ToHashSet();
        foreach (var rc in insert.ResultColumns.Where(c => c.PropertyName is not null))
            if (!gen.Contains(rc.PropertyName))
                throw new InvalidOperationException($"Insert sproc result column '{rc.PropertyName}' on '{et.Name}' must be ValueGeneratedOnAdd.");
    }
    if (update is not null)
    {
        var gen = et.GetProperties().Where(p => p.ValueGenerated.HasFlag(ValueGenerated.OnUpdate)).Select(p => p.Name).ToHashSet();
        foreach (var rc in update.ResultColumns.Where(c => c.PropertyName is not null))
            if (!gen.Contains(rc.PropertyName))
                throw new InvalidOperationException($"Update sproc result column '{rc.PropertyName}' on '{et.Name}' must be ValueGeneratedOnUpdate.");
    }
}

Try / catch

try { _ = ctx.Model; }
catch (InvalidOperationException ex) when (ex.Message.Contains("not configured as store-generated"))
{
    logger.LogError("Result-column property must be store-generated. {Msg}", ex.Message);
    throw;
}

Prevention

When it happens

Trigger: Adding .HasResultColumn(x => x.UpdatedAt) to an Update sproc without marking AtUpdatedAt as ValueGenerated.OnUpdate (or .HasDatabaseGeneratedOption). Or binding a normal property as a result column expecting EF to read it back, without configuring value generation.

Common situations: Treating a regular column as a result column so EF reads it after save; forgetting .ValueGeneratedOnAdd()/OnUpdate() on identity/computed/timestamp columns when moving to sproc mapping.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/d0f9904921ca1d97. Report an issue: GitHub.

Appendix: source

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

            if (!resultColumnNames.Add(resultColumn.Name))
            {
                throw new InvalidOperationException(
                    RelationalStrings.StoredProcedureDuplicateResultColumnName(
                        resultColumn.Name, storeObjectIdentifier.DisplayName()));
            }

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

            switch (storeObjectIdentifier.StoreObjectType)
            {
                case StoreObjectType.InsertStoredProcedure:
                case StoreObjectType.UpdateStoredProcedure:
                    if (!storeGeneratedProperties.ContainsKey(property.Name))
                    {
                        throw new InvalidOperationException(
                            RelationalStrings.StoredProcedureResultColumnNotGenerated(
                                entityType.DisplayName(), resultColumn.PropertyName, storeObjectIdentifier.DisplayName()));
                    }

                    break;
                case StoreObjectType.DeleteStoredProcedure:
                    throw new InvalidOperationException(
                        RelationalStrings.StoredProcedureResultColumnDelete(
                            entityType.DisplayName(), resultColumn.PropertyName, storeObjectIdentifier.DisplayName()));
                default:
                    Check.DebugFail("Unexpected stored procedure type: " + storeObjectIdentifier.StoreObjectType);
                    break;
            }
        }

        var originalValueProperties = new Dictionary<string, IProperty>(properties);
        var parameterNames = new HashSet<string>();
        foreach (var parameter in sproc.Parameters)

View on GitHub (pinned to 3a2006ef56)