为什么从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()。即使这种蛮力(而且效率低下)的方法也只更新了数组中的最后一项。

还有另一种方法:我也尝试了一个表值参数,但它也只更新了输入中最后一项对应的记录。

提前感谢您的帮助

为什么从c# web表单调用时,存储过程只处理以逗号分隔的列表的最后一项?

将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;