dotnet/efcore · error · InvalidOperationException

The property '{entityType}.{property}' is mapped to a result

Error message

The property '{entityType}.{property}' is mapped to a result column of the stored procedure '{sproc}', but it is also mapped to an output parameter. A store-generated property can only be mapped to one of these.

What it means

A store-generated property can be read back from a stored procedure via exactly one mechanism — either an output parameter or a result column. The validator at line 839-844 throws when a result column references a property that was already removed from the storeGenerated set by an earlier output parameter (or is not store-generated at all). Mapping the same generated value to both creates ambiguity about which source EF should use to populate the property after save.

Source

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

                    break;
                default:
                    Check.DebugFail("Unexpected stored procedure type: " + storeObjectIdentifier.StoreObjectType);
                    break;
            }
        }

        foreach (var resultColumn in sproc.ResultColumns)
        {
            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())
            {

View on GitHub (pinned to dbf9771522)

Solutions

  1. Pick one read-back mechanism: keep the OutputParameter mapping and remove the ResultColumn (or vice-versa).
  2. Prefer OutputParameter when the sproc returns the value via an OUT param; prefer ResultColumn when the sproc returns a result set row.
  3. Audit the sproc mapping for any property that appears in both .OutputParameter() and .ResultColumn() calls.

Example fix

// before
modelBuilder.Entity<Order>()
    .InsertStoredProcedure(o => o
        .OutputParameter(p => p.Id, "new_id")
        .ResultColumn(p => p.Id, "id"));   // duplicate read-back

// after - keep only the output parameter
modelBuilder.Entity<Order>()
    .InsertStoredProcedure(o => o
        .OutputParameter(p => p.Id, "new_id"));
Defensive patterns

Strategy: validation

Validate before calling

foreach (var et in modelBuilder.Model.GetEntityTypes())
{
    foreach (var sproc in et.GetStoredProcedures())
    {
        var outputProps = sproc.Parameters
            .Where(p => p.Direction != ParameterDirection.Input && p.PropertyName != null)
            .Select(p => p.PropertyName).ToHashSet();
        foreach (var rc in sproc.ResultColumns)
        {
            if (rc.PropertyName != null && outputProps.Contains(rc.PropertyName))
            {
                throw new InvalidOperationException(
                    $"Property '{rc.PropertyName}' on {et.Name} mapped to both output param and result column.");
            }
        }
    }
}

Prevention

When it happens

Trigger: On an Insert/Update sproc, calling both `.OutputParameter(p => p.Id, ...)` and `.ResultColumn(p => p.Id, ...)` for the same property. The output-parameter handler removes the property from storeGeneratedProperties first, so when the result column tries to remove it again the set lookup fails.

Common situations: Translating a sproc that uses both an OUTPUT clause and a RETURN/SELECT by accident; merging two config snippets that each added a different read-back mapping for the identity column.

Related errors


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