为什么从c# web表单调用时,存储过程只处理以逗号分隔的列表的最后一项?
本文关键字:列表 最后 分隔 一项 表单 web 调用 处理 存储过程 为什么 | 更新日期: 2023-09-27 18:10:24
我在Visual Studio 2013和SQL Server 2012中使用c#。
当用户使用我的ASP。. NET web表单输入一个换行分隔的代码列表并单击提交,后面的代码应该读取这些值,将它们连接成一个逗号分隔的字符串,并将该字符串传递给调用存储过程的方法。存储过程解析出这些值并将每个记录上的活动字段设置为1与匹配的代码。
Product表定义为:
id (PK, int, not null),
name (varchar(20), not null),
code (varchar(20), null),
active (bit, not null)
Product表包含以下五条记录:
id name code active
-- ---- ---- ------
1 Product 1 AAA 0
2 Product 2 BBB 0
3 Product 3 CCC 0
4 Product 4 DDD 0
5 Product 5 EEE 0
我创建了以下存储过程:
CREATE PROCEDURE [dbo].[MarkListAsActive]
@codeList varchar(MAX)
AS
UPDATE
dbo.Product
SET
active = 1
WHERE
code IN (SELECT val FROM dbo.f_split(@codeList, ','))
dbo.f_split
处理以逗号分隔的字符串的解析。我从这个帖子复制了它:https://stackoverflow.com/a/17481595/2677169
如果我在SQL Server Management Studio中执行存储过程,所有五条记录都会更新(如预期的那样)。
DECLARE @return_value int
EXEC @return_value = [dbo].[MarkListAsActive]
@codeList = N'AAA,BBB,CCC,DDD,EEE'
SELECT 'Return Value' = @return_value
GO
但是,如果我从.aspx页面后面的代码调用存储过程,则只有列表中的最后一项被标记为活动。
protected void SubmitButton_Click(object sender, EventArgs e)
{
string[] codeArray;
char separator = ''n';
OutputLabel.Text = "";
codeArray = ProductCodeTextBox.Text.Split(separator);
OutputLabel.Text += "The products with the following codes were marked as active:<br />";
string codes = "";
// TODO: Replace with regex that changes newlines to commas
for (int i = 0; i < codeArray.Length; i++)
{
codes += codeArray[i] + ",";
OutputLabel.Text += codeArray[i] + "<br />";
}
codes = codes.Substring(0, codes.Length - 1);
Utilities.Log(codes);
DataAccess.MarkListAsActive(codes);
}
public static void MarkListAsActive(string codeList)
{
try
{
string connectionString = ConfigurationManager.ConnectionStrings["ApplicationServices"].ConnectionString;
using (SqlConnection conn = new SqlConnection(connectionString))
using (SqlCommand command = new SqlCommand("[dbo].[MarkListAsActive]", conn)
{
CommandType = CommandType.StoredProcedure
})
{
conn.Open();
command.Parameters.Add("@codeList", codeList);
command.ExecuteNonQuery();
conn.Close();
}
}
catch (Exception ex)
{
Utilities.Log(String.Format("Error in MarkListAsActive: {0}'n{1}", ex.Message, ex.StackTrace));
}
return;
}
请注意,我验证了传递给MarkListAsActive()
的字符串是正确的。
另一种方法:我尝试通过codeArray循环并为每个项目调用MarkListAsActive()
。即使这种蛮力(而且效率低下)的方法也只更新了数组中的最后一项。
还有另一种方法:我也尝试了一个表值参数,但它也只更新了输入中最后一项对应的记录。
提前感谢您的帮助
将IN子句更改为(SELECT val FROM dbo)。f_split(@codeList, ','),其中val不为空)。
如果这不起作用,请遵循以下步骤:
(无论如何,您应该知道如何调试这样的代码。)
首先,使用SQL Profiler查看提交给数据库的内容。看看这里如何做到这一点-它并不像它看起来那么糟糕,是无价的。如果不符合预期,则说明您的前端有问题。
第二,如果对数据库的调用看起来不错,那么使用SQL Profiler中看到的参数并使用它执行dbo.f_split(),看看是否得到了您认为应该得到的结果。
最后,将UPDATE语句更改为SELECT语句,并使用第二步中的方法运行它,看看是否得到了正确的结果。
其中一个步骤将不会返回预期的结果,这将导致您遇到问题。
where子句不正确。你不能做
... code in (select val ...
需要将f_split函数的结果连接到表中。
例如:UPDATE p
SET p.active = 1
FROM dbo.Product p inner join dbo.f_split(@codeList, ',') f
WHERE p.code = f.val;