调用存储过程未按预期更新

时间:2017-05-19 16:27:15

标签: c# asp.net sql-server stored-procedures

我对存储过程有一个谜,我从后面的代码(C#)调用。我感到困惑,因为我已经在C#端添加了我的代码的观察点,并且所有内容似乎都具有应该进入存储过程调用的值但是,该过程运行时没有任何错误我可以告诉我的表并没有更新我认为应该使用的值。

SP会传递三个值。

Record ID (@Record_ID), Column to update (@UpdColumn), and the value to place in that column (@UpdValue).

这是我打电话给我的SP:

ALTER PROCEDURE [dbo].[Single_Col_Update] 
-- Add the parameters for the stored procedure here
@Record_ID  INT,
@UpdColumn  CHAR,
@UpdValue   NVARCHAR
AS
BEGIN
SET NOCOUNT ON;

IF @UpdColumn = 'TicketNumber' 
    UPDATE dbo.csr_refdata_ip360_HostVulnerabilityCSV
    SET TicketNumber = @UpdValue
    WHERE RecID = @Record_ID;

IF @UpdColumn = 'TicketClosed'
    UPDATE dbo.csr_refdata_ip360_HostVulnerabilityCSV
    SET TicketClosed = @UpdValue
    WHERE RecID = @Record_ID;

IF @UpdColumn = 'Notes'
    UPDATE dbo.csr_refdata_ip360_HostVulnerabilityCSV
    SET Notes = @UpdValue
    WHERE RecID = @Record_ID;

IF @UpdColumn = 'Exception_ID'
    UPDATE dbo.csr_refdata_ip360_HostVulnerabilityCSV
    SET ExceptionID = @UpdValue
    WHERE RecID = @Record_ID;
END

以下是调用SP的代码段:

foreach (string record in recordnumber)
{
SqlConnection con = new SqlConnection("Data Source=MyDataSource");
SqlCommand cmd = new SqlCommand();

cmd.CommandText = "Single_Col_Update";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Connection = con;

cmd.Parameters.AddWithValue("@Record_ID", Convert.ToInt32(record));
cmd.Parameters.AddWithValue("@UpdColumn", Session["UpdColumn"]);
cmd.Parameters.AddWithValue("@UpdValue", Session["UpdValue"]);

con.Open();
cmd.ExecuteNonQuery();
con.Close();
}

由于所有变量都是正确的,我不确定为什么这不是更新。希望你们中的一些人在这里看到错误。

UPDATED 5/19/2017 1:40 PM Central - 史蒂夫,  我尝试按照您下面的规定实施呼叫。我只对您提供的内容进行了修改:

  1. ' cmd.Parameters.Add(" @ UpdValue",SqlDbType.NVarChar,1024);' //而不是255,因为我在那里喂的那一列有一个NVarChar(MAX)我可能要回去修改它大于1024.它似乎不是MAX值我可以放在那里,所以测试1024就足够了。
  2. 省略了' transaction.Rollback();' //我在“交易”这个词上留下了红线。尽管我尝试过,但我无法通过它来验证它。
  3. 底线是在实现下面的代码后,结果与之前完全相同。执行的代码没有通过我添加的Consol.Write或通过VS 2017 IDE报告任何错误。

    SqlTransaction transaction;
    try
    {
        using (SqlConnection con = new SqlConnection("Data Source=MyDataSource"))
        using (SqlCommand cmd = new SqlCommand("Single_Col_Update", con))
        {
            con.Open();
            transaction = con.BeginTransaction();
            cmd.Transaction = transaction;
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.Add("@Record_ID", SqlDbType.Int);
            cmd.Parameters.Add("@UpdColumn", SqlDbType.NVarChar, 255);
            cmd.Parameters.Add("@UpdValue", SqlDbType.NVarChar, 1024);
    
            foreach (string record in recordnumber)
                {
                    cmd.Parameters["@Record_ID"].Value = Convert.ToInt32(record);
                    cmd.Parameters["@UpdColumn"].Value = Session["UpdColumn"].ToString();
                    cmd.Parameters["@UpdValue"].Value = Session["UpdValue"].ToString();
                    cmd.ExecuteNonQuery();
                }
    
            transaction.Commit();
        }
    }
    catch (Exception ex)
    {
        Console.Write(ex.ToString());
    }
    

    所以我仍然在那里,但我注意到你分享了什么,我同意你所说的一切。我没有注意到我在那里打开和关闭连接,并且没有意识到你分享的其他内容。

    然而,窘境仍然存在!

    更新05/22/2017 10:45 AM中部时间: 我意识到我试图在我的存储过程中将NVarchar类型填充到Varchar类型中。一旦纠正,我根据史蒂夫的反馈做出的修改工作得很好。我还没有尝试过,但是我假设如果类型与之匹配,那么我必须开始使用的东西会起作用,但史蒂夫的例子​​更清洁,所以我甚至不回头测试旧的方式。再次感谢史蒂夫!

2 个答案:

答案 0 :(得分:2)

问题在于声明此参数

@UpdColumn  CHAR,

以这种方式存储过程需要一个SINGLE字符,而不是字符串 因此,以下所有if语句都是错误的,不会更新任何内容

将其更改为

@UpdColumn  NVARCHAR(255)

@UpdValue 参数也是如此。同样,存储过程只接收一个char。如果你传递一整串字符串并不重要 如果您没有指定NVARCHAR或CHAR参数的大小,则数据库引擎将仅使用传递值的第一个字符。

我还要强调Alex K的上述评论。虽然它不应该给你带来很多好处,但最好打开连接并使用循环外的参数创建命令。在循环内部只需更改参数值并执行sp

SqlTransaction transaction;
try
{
    using(SqlConnection con = new SqlConnection(.....))
    using(SqlCommand cmd = new SqlCommand("Single_Col_Update", con))
    {
        con.Open();
        transaction = con.BeginTransaction())
        cmd.Transaction = transaction;
        cmd.CommandType = CommandType.StoredProcedure;
        cmd.Parameters.Add("@Record_ID", SqlDbType.Int);
        cmd.Parameters.Add("@UpdColumn", SqlDbType.NVarChar, 255);
        cmd.Parameters.Add("@UpdValue", SqlDbType.NVarChar, 255);
        foreach (string record in recordnumber)
        {
            cmd.Parameters["@Record_ID"].Value = Convert.ToInt32(record));
            cmd.Parameters["@UpdColumn"].Value = Session["UpdColumn"].ToString();
            cmd.Parameters["@UpdValue"].Value = Session["UpdValue"].ToString();
            cmd.ExecuteNonQuery();
        }
        transaction.Commit();
    }
}
catch(Exception ex)
{
     // show a message to your users
     transaction.Rollback();
}

我还在事务中添加了所有循环以确认所有插入作为一个整体,或者在出现错误时拒绝所有插入。

答案 1 :(得分:0)

CHAR仅应在列为固定长度时使用。当您使用不同长度的字符串时,结果通常不是您所期望的,因为参数/列将填充空格,这就是您的IF语句失败的原因。

不要为@UpdColumn使用CHAR类型。对此列使用NVARCHAR,并且在存储过程中为此参数和UpdValue参数指定长度,然后在从C#代码调用存储过程时将其与此匹配,这是一个很好的做法。