{"record":{"id":"1a9f21f44f43cfa5","repo":"dotnet/efcore","slug":"input-parameter-parameter-of-update-stored-pro","errorCode":null,"errorMessage":"Input parameter '{parameter}' of update stored procedure '{sproc}' is mapped to property '{property}' of entity type '{entityType}', but that property is configured with AfterSaveBehavior '{behavior}', and so cannot be saved on update. You may need to use HasOriginalValueParameter() instead of HasParameter().","messagePattern":"Input parameter '(.+?)' of update stored procedure '(.+?)' is mapped to property '(.+?)' of entity type '(.+?)', but that property is configured with AfterSaveBehavior '(.+?)', and so cannot be saved on update\\. You may need to use HasOriginalValueParameter\\(\\) instead of HasParameter\\(\\)\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs","lineNumber":758,"sourceCode":"                        {\n                            case StoreObjectType.InsertStoredProcedure:\n                                if (property.GetBeforeSaveBehavior() != PropertySaveBehavior.Save)\n                                {\n                                    throw new InvalidOperationException(\n                                        RelationalStrings.StoredProcedureInputParameterForInsertNonSaveProperty(\n                                            parameter.Name,\n                                            storeObjectIdentifier.DisplayName(),\n                                            parameter.PropertyName,\n                                            entityType.DisplayName(),\n                                            property.GetBeforeSaveBehavior()));\n                                }\n\n                                break;\n\n                            case StoreObjectType.UpdateStoredProcedure:\n                                if (property.GetAfterSaveBehavior() != PropertySaveBehavior.Save)\n                                {\n                                    throw new InvalidOperationException(\n                                        RelationalStrings.StoredProcedureInputParameterForUpdateNonSaveProperty(\n                                            parameter.Name,\n                                            storeObjectIdentifier.DisplayName(),\n                                            parameter.PropertyName,\n                                            entityType.DisplayName(),\n                                            property.GetAfterSaveBehavior()));\n                                }\n\n                                break;\n\n                            case StoreObjectType.DeleteStoredProcedure:\n                                break;\n\n                            default:\n                                Check.DebugFail(\"Unexpected stored procedure type: \" + storeObjectIdentifier.StoreObjectType);\n                                break;\n                        }\n                    }","sourceCodeStart":740,"sourceCodeEnd":776,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs#L740-L776","documentation":"Thrown during model validation when an UPDATE stored procedure mapping declares an INPUT parameter bound to an entity property whose AfterSaveBehavior is not PropertySaveBehavior.Save. EF Core refuses to send a value the model says is read-only after the entity exists, because the update sproc parameter would imply the property is writable. The validator guards the HasParameter() mapping call against the property's after-save contract.","triggerScenarios":"Calling entityType.UpdateUsingStoredProcedure(...).HasParameter(p => p.Foo) where Foo has AfterSaveBehavior != Save (e.g. .ValueGeneratedOnAdd(), .Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Ignore), a store-generated computed column, or a property marked read-only after save). Surfaces when the model is finalized (EnsureModelFinalized / first query / SaveChanges) and validator runs.","commonSituations":"Marking an audit/created-on column or a computed column as input parameter on an update sproc; mapping a property that should only be written on INSERT; switching a column to ValueGeneratedOnAdd but forgetting to drop it from the update sproc parameters; using the same HasParameter call for insert and update sproc configs.","solutions":["Remove the offending HasParameter(p => p.Foo) call from the UpdateUsingStoredProcedure configuration since the property is not writable on update.","If EF should pass the original DB value for concurrency, use HasOriginalValueParameter(p => p.Foo) instead of HasParameter(p => p.Foo).","If the property genuinely must be written on update, set its after-save behavior to Save: builder.Property(p => p.Foo).Metadata.SetAfterSaveBehavior(PropertySaveBehavior.Save) (or remove the .ValueGeneratedOnAdd()/AfterSaveBehavior.Ignore that suppressed it).","Move that property to an output parameter / result column mapping if the database regenerates it on update."],"exampleFix":"// before\nentityType.UpdateUsingStoredProcedure(\"UpdateCustomer\",\n    sp =>\n    {\n        sp.HasParameter(c => c.CreatedOn); // CreatedOn is ValueGeneratedOnAdd\n    });\n\n// after\nentityType.UpdateUsingStoredProcedure(\"UpdateCustomer\",\n    sp =>\n    {\n        // CreatedOn removed; it is not writable on update\n        sp.HasParameter(c => c.Name);\n    });","handlingStrategy":"validation","validationCode":"// Before finalizing the model, verify each UPDATE sproc input parameter\n// maps to a Save-after-save property.\nforeach (var et in model.GetEntityTypes())\n{\n    var updateSproc = et.GetUpdateStoredProcedure();\n    if (updateSproc == null) continue;\n    foreach (var p in updateSproc.Parameters)\n    {\n        if (p.Direction.HasFlag(System.Data.ParameterDirection.Input)\n            && p.PropertyName is string name)\n        {\n            var prop = et.FindProperty(name);\n            if (prop?.GetAfterSaveBehavior() != Microsoft.EntityFrameworkCore.Metadata.PropertySaveBehavior.Save)\n            {\n                Console.WriteLine($\"{et.Name}.{name} is not Save on update; remove or use HasOriginalValueParameter.\");\n            }\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Drive sproc parameter mapping from a single config method per entity so insert/update/delete variants diverge deliberately.","When you change a property's ValueGenerated / SaveBehavior, search for HasParameter calls that reference it.","Add a model-validation integration test that builds the model and calls model.FinalizeModel() during unit tests."],"tags":["ef-core","stored-procedures","model-validation","savechanges"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}