C#调用SQL Server存储过程时提示‘指定的参数过多’
问题背景
我在SQL Server中的存储过程如下:
ALTER PROCEDURE [dbo].[stpr_WPC_UpdatePOReply] @eComments NVarChar(200) AS BEGIN SET NOCOUNT ON; UPDATE dbo.SupplierProductionScheduleReplies SET Comments = @eComments WHERE id = 39906; END
注:为排查问题暂时硬编码了id值,后续会改为参数传入。
使用Bizagi修改版C#编写的调用代码:
//UPDATING FULL PO (PO CHECK) // Set the connection string var strcnx = CHelper.getParameterValue("SV11SAGE01-StockControl"); // set the variable and value from a form var eComments = <m_WPC_WeeklyProductChase.idm_WPC_POCheck.eKPComments> var connection = new System.Data.SqlClient.SqlConnection(); // identify the stored procedure var cmd = new SqlCommand("dbo.stpr_WPC_UpdatePOReply"); connection.ConnectionString = strcnx; cmd.CommandType = CommandType.StoredProcedure; // add a parameter, based on the variable eComments cmd.Parameters.Add("@eComments", SqlDbType.NVarChar, 200).Value = eComments; try { // running a stored procedure connection.Open(); cmd.Connection = connection; cmd.ExecuteNonQuery(); } catch(exc) { CHelper.ThrowValidationError(exc); } finally { connection.Close(); }
运行代码时触发错误:
Procedure or function stpr_WPC_UpdatePOReply has too many arguments specified.
无参数调用(直接用硬编码参数的存储过程)正常,但添加参数后就报错。原本有15个参数,已简化为1个排查。
已确认的信息:
- 存储过程参数查询结果:
ParameterName: @eComments; DataType: nvarchar; max_length: 400; is_output: 0 - SQL Server中Comments列定义为
(nvarchar(max), null) - 尝试过传入2个参数、使用
AddWithValue、添加/移除cmd.Parameters.Clear(),均无效
解决方法
1. 确认存储过程的实际定义
有时候修改的存储过程可能并非当前连接数据库/架构下的版本,或是存在同名存储过程。执行以下SQL确认当前数据库中该存储过程的参数:
SELECT name AS ParameterName, system_type_name AS DataType, max_length, is_output FROM sys.parameters WHERE object_id = OBJECT_ID('dbo.stpr_WPC_UpdatePOReply');
如果结果和预期不一致,说明调用的不是你修改的存储过程,可能是架构错误(比如用了dbo以外的架构)或数据库选错了。
2. 排查Bizagi参数传递逻辑
Bizagi的<m_WPC_WeeklyProductChase.idm_WPC_POCheck.eKPComments>语法可能自动添加额外参数,或是底层存在参数注入情况。可以临时把eComments替换成固定字符串测试:
var eComments = "test comment";
如果这样能正常执行,说明是Bizagi变量传递过程中额外引入了参数,需要检查表单绑定逻辑。
3. 显式指定存储过程的完整路径
创建SqlCommand时,完整指定数据库和架构,避免歧义:
var cmd = new SqlCommand("YourDatabaseName.dbo.stpr_WPC_UpdatePOReply");
同时确保连接字符串指向的数据库和存储过程所在数据库一致。
4. 验证连接字符串对应的数据库
确认CHelper.getParameterValue("SV11SAGE01-StockControl")返回的连接字符串指向的数据库,确实是存储过程所在的数据库。可以临时输出连接字符串排查:
CHelper.ThrowValidationError(new Exception(strcnx)); // 临时输出连接字符串
5. 重新创建存储过程
有时候存储过程的元数据可能存在缓存,尝试重新创建存储过程:
DROP PROCEDURE IF EXISTS [dbo].[stpr_WPC_UpdatePOReply]; GO CREATE PROCEDURE [dbo].[stpr_WPC_UpdatePOReply] @eComments NVarChar(200) AS BEGIN SET NOCOUNT ON; UPDATE dbo.SupplierProductionScheduleReplies SET Comments = @eComments WHERE id = 39906; END GO
总结
最常见的原因是调用了错误的存储过程(同名但参数不同),或是Bizagi的变量传递逻辑额外添加了参数。先通过SQL确认存储过程的实际参数,再用固定值测试参数传递,逐步排查即可解决。
内容的提问来源于stack exchange,提问作者MickO

