{"record":{"id":"f7795bb35fae9de1","repo":"dotnet/efcore","slug":"a-rows-affected-parameter-result-column-or-return","errorCode":null,"errorMessage":"A rows affected parameter, result column or return value cannot be configured on stored procedure '{sproc}' because it is used for insertion. Rows affected values are only allowed on stored procedures performing updating or deletion.","messagePattern":"A rows affected parameter, result column or return value cannot be configured on stored procedure '(.+?)' because it is used for insertion\\. Rows affected values are only allowed on stored procedures performing updating or deletion\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs","lineNumber":915,"sourceCode":"            }\n\n            if (properties.Count > 0)\n            {\n                throw new InvalidOperationException(\n                    RelationalStrings.StoredProcedurePropertiesNotMapped(\n                        entityType.DisplayName(),\n                        storeObjectIdentifier.DisplayName(),\n                        properties.Values.Format()));\n            }\n        }\n\n        if (sproc.IsRowsAffectedReturned\n            || sproc.FindRowsAffectedParameter() != null\n            || sproc.FindRowsAffectedResultColumn() != null)\n        {\n            if (storeObjectIdentifier.StoreObjectType == StoreObjectType.InsertStoredProcedure)\n            {\n                throw new InvalidOperationException(\n                    RelationalStrings.StoredProcedureRowsAffectedForInsert(\n                        storeObjectIdentifier.DisplayName()));\n            }\n\n            if (originalValueProperties.Values.FirstOrDefault(p => p.IsConcurrencyToken) is { } missedConcurrencyToken)\n            {\n                logger.StoredProcedureConcurrencyTokenNotMapped(entityType, missedConcurrencyToken, storeObjectIdentifier.DisplayName());\n            }\n\n            if (sproc.ResultColumns.Any(c => c != sproc.FindRowsAffectedResultColumn()))\n            {\n                throw new InvalidOperationException(\n                    RelationalStrings.StoredProcedureRowsAffectedWithResultColumns(\n                        entityType.DisplayName(),\n                        storeObjectIdentifier.DisplayName()));\n            }\n        }\n    }","sourceCodeStart":897,"sourceCodeEnd":933,"githubUrl":"https://github.com/dotnet/efcore/blob/dbf9771522148d61a2467854921bd5dc6f6e6916/src/EFCore.Relational/Infrastructure/RelationalModelValidator.cs#L897-L933","documentation":"A 'rows affected' value (output parameter, result column, or return value) is used to detect optimistic-concurrency conflicts during Update/Delete. Inserts always succeed for a new row so a rows-affected signal is meaningless and not allowed. The validator at line 909-918 explicitly rejects any rows-affected configuration when the store object is an InsertStoredProcedure.","triggerScenarios":"Calling `.InsertStoredProcedure(...).RowsAffectedParameter(\"rows\")` / `.RowsAffectedResultColumn(\"rows\")` / `.ReturnsRowsAffected()` (or returning rows-affected from the sproc).","commonSituations":"Reusing the same sproc builder snippet across insert/update/delete operations; assuming all sprocs need the rows-affected pattern that update/delete use for concurrency.","solutions":["Remove the .RowsAffectedParameter() / .RowsAffectedResultColumn() / .ReturnsRowsAffected() call from the Insert sproc mapping.","Move any rows-affected logic to the Update and/or Delete sproc mappings where it is meaningful.","If you need to verify an insert succeeded, use the output identity value or wrap the call in a transaction with exception handling."],"exampleFix":"// before\nmodelBuilder.Entity<Order>()\n    .InsertStoredProcedure(o => o\n        .Parameter(p => p.Amount, \"amt\")\n        .RowsAffectedParameter(\"rc\"));\n\n// after\nmodelBuilder.Entity<Order>()\n    .InsertStoredProcedure(o => o\n        .Parameter(p => p.Amount, \"amt\")\n        .OutputParameter(p => p.Id, \"new_id\"));","handlingStrategy":"validation","validationCode":"foreach (var et in modelBuilder.Model.GetEntityTypes())\n{\n    var insert = et.GetStoredProcedures()\n        .FirstOrDefault(s => s.StoreObjectType == StoreObjectType.InsertStoredProcedure);\n    if (insert != null\n        && (insert.IsRowsAffectedReturned\n            || insert.FindRowsAffectedParameter() != null\n            || insert.FindRowsAffectedResultColumn() != null))\n    {\n        throw new InvalidOperationException(\n            $\"Insert sproc for {et.Name} must not configure rows-affected.\");\n    }\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Never call .RowsAffectedParameter()/.RowsAffectedResultColumn()/.ReturnsRowsAffected() on an Insert sproc.","Reuse sproc builder helpers only for Update/Delete; write a separate Insert helper without rows-affected.","Add a unit test asserting no Insert sproc has rows-affected configured."],"tags":["ef-core","stored-procedures","model-validation","insert"],"analyzedSha":"dbf9771522148d61a2467854921bd5dc6f6e6916","analyzedAt":"2026-08-06T20:46:03.226Z","schemaVersion":2},"datasetVersion":"2026-08-07T03:17:09.362Z"}