{"record":{"id":"677c0651ebd70e7a","repo":"dotnet/efcore","slug":"the-rows-affected-parameter-cannot-be-added-to-the","errorCode":null,"errorMessage":"The rows affected parameter cannot be added to the stored procedure '{sproc}' because the rows affected are already returned via another parameter, via the stored procedure return value or via a result column.","messagePattern":"The rows affected parameter cannot be added to the stored procedure '(.+?)' because the rows affected are already returned via another parameter, via the stored procedure return value or via a result column\\.","errorType":"exception","errorClass":"InvalidOperationException","httpStatus":null,"severity":"error","filePath":"src/EFCore.Relational/Metadata/Internal/StoredProcedure.cs","lineNumber":577,"sourceCode":"    ///     any release. You should only use it directly in your code with extreme caution and knowing that\n    ///     doing so can result in application failures when updating to a new Entity Framework Core release.\n    /// </summary>\n    public virtual StoredProcedureParameter? FindRowsAffectedParameter()\n        => _rowsAffectedParameter;\n\n    /// <summary>\n    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to\n    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in\n    ///     any release. You should only use it directly in your code with extreme caution and knowing that\n    ///     doing so can result in application failures when updating to a new Entity Framework Core release.\n    /// </summary>\n    public virtual StoredProcedureParameter AddRowsAffectedParameter()\n    {\n        if (_rowsAffectedParameter != null\n            || _rowsAffectedResultColumn != null\n            || _isRowsAffectedReturned)\n        {\n            throw new InvalidOperationException(\n                RelationalStrings.StoredProcedureDuplicateRowsAffectedParameter(\n                    ((IReadOnlyStoredProcedure)this).GetStoreIdentifier()?.DisplayName()));\n        }\n\n        var parameter = new StoredProcedureParameter(this, rowsAffected: true, propertyName: null, originalValue: null);\n        _parameters.Add(parameter);\n        _rowsAffectedParameter = parameter;\n\n        return parameter;\n    }\n\n    /// <summary>\n    ///     This is an internal API that supports the Entity Framework Core infrastructure and not subject to\n    ///     the same compatibility standards as public APIs. It may be changed or removed without notice in\n    ///     any release. You should only use it directly in your code with extreme caution and knowing that\n    ///     doing so can result in application failures when updating to a new Entity Framework Core release.\n    /// </summary>\n    public virtual IReadOnlyList<StoredProcedureResultColumn> ResultColumns","sourceCodeStart":559,"sourceCodeEnd":595,"githubUrl":"https://github.com/dotnet/efcore/blob/3a2006ef569de08368d59db5e1468aa8f407e4f8/src/EFCore.Relational/Metadata/Internal/StoredProcedure.cs#L559-L595","documentation":"EF Core forbids a stored procedure from returning the rows-affected count through more than one channel. AddRowsAffectedParameter() throws when rows affected is already sourced from a parameter, a result column, or the procedure's return value, because the runtime could not disambiguate which channel to read.","triggerScenarios":"Calling entity.UpdateUsingStoredProcedure(...).RowsAffectedParameter() after a prior .RowsAffectedParameter(), .RowsAffectedResultColumn(), or .RowsAffectedReturned() on the same stored procedure. The guard fires when any of _rowsAffectedParameter, _rowsAffectedResultColumn, or _isRowsAffectedReturned is already set.","commonSituations":"Migrating a manual stored-procedure mapping where the DBA set rows-affected via the RETURN value, then the developer adds an output parameter; or copy-pasting fluent calls between Insert/Update/Delete procedures; or upgrading EF versions where the default rows-affected strategy changed.","solutions":["Inspect the existing mapping first: call FindRowsAffectedParameter(), FindRowsAffectedResultColumn(), and check IsRowsAffectedReturned before adding a new channel.","Choose exactly ONE rows-affected source per procedure and remove the duplicate fluent call.","If the procedure returns rows affected via its RETURN value, use .RowsAffectedReturned() only and do not add a parameter or result column.","If a parameter must carry rows affected, ensure no .RowsAffectedResultColumn() or .RowsAffectedReturned() was configured for that procedure."],"exampleFix":"// before\nmodelBuilder.Entity<Order>()\n    .UpdateUsingStoredProcedure(\"usp_UpdateOrder\", sp =>\n    {\n        sp.RowsAffectedReturned();\n        sp.RowsAffectedParameter(); // throws: already returned\n    });\n\n// after\nmodelBuilder.Entity<Order>()\n    .UpdateUsingStoredProcedure(\"usp_UpdateOrder\", sp =>\n    {\n        sp.RowsAffectedReturned();\n    });","handlingStrategy":"validation","validationCode":"// Before adding a rows-affected channel, verify none exists.\nvar sp = entityType.GetUpdateStoredProcedure();\nif (sp is not null\n    && sp.FindRowsAffectedParameter() is null\n    && sp.FindRowsAffectedResultColumn() is null\n    && !sp.IsRowsAffectedReturned)\n{\n    sp.RowsAffectedParameter();\n}","typeGuard":"static bool CanAddRowsAffectedParameter(IStoredProcedure sp)\n    => sp.FindRowsAffectedParameter() is null\n       && sp.FindRowsAffectedResultColumn() is null\n       && !sp.IsRowsAffectedReturned;","tryCatchPattern":null,"preventionTips":["Decide each procedure's single rows-affected channel at design time and document it.","Centralize stored-procedure builder helpers so the rows-affected choice is made in one place.","Run model validation ( modelBuilder.FinalizeModel() ) in unit tests to surface config errors early."],"tags":["ef-core","stored-procedure","configuration","rows-affected","model-building"],"backgroundTag":null,"analyzedSha":"3a2006ef569de08368d59db5e1468aa8f407e4f8","analyzedAt":"2026-08-11T23:42:04.146Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}