【问题标题】:C# TSQL Stored Procedure don't pass parameter?C# TSQL 存储过程不传递参数?
【发布时间】:2016-04-04 08:50:34
【问题描述】:

我不知道这个查询是否值得询问,但最好了解什么有效,什么无效以及为什么。

我有一张这样的表,叫做tbl_Person_Details

ID | Name | Likes
-----------------
0  | Jon  | Fish
1  | Doey | Coding

这样的代码(示例显示了两个函数,但可能还有更多):

public void updatePerson()
{
    string sID = GridView1.SelectedDataKey[0].ToString();

    SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
    con.Open();

    SqlCommand comm = new SqlCommand("spUpdatePersonBasics", con);
    comm.CommandType = CommandType.StoredProcedure;

    comm.Parameters.Add(new SqlParameter("@Name", tbName.Text.ToString()));
    comm.Parameters.Add(new SqlParameter("@ID", sID));

    object tmp = comm.ExecuteScalar();
    con.Close();

    lblStatus.Text = "<img src=\"img/icons/green-tick.gif\" /> <strong>>Person Details have been updated!</strong>";
}

public void updatePersonLikes()
{
    string sID = GridView1.SelectedDataKey[0].ToString();

    SqlConnection con = new SqlConnection(ConfigurationManager.ConnectionStrings["ConnectionString"].ConnectionString);
    con.Open();

    SqlCommand comm = new SqlCommand("spUpdatePersonBasics", con);
    comm.CommandType = CommandType.StoredProcedure;

    comm.Parameters.Add(new SqlParameter("@Likes", tbName.Text.ToString()));
    comm.Parameters.Add(new SqlParameter("@ID", sID));

    object tmp = comm.ExecuteScalar();
    con.Close();

    lblStatus.Text = "<img src=\"img/icons/green-tick.gif\" /> <strong>>Person likes have been updated!</strong>";
}

存储过程:

ALTER PROCEDURE [dbo].[spUpdatePersonBasics]
    @ID int, 
    @Name varchar(50),
    @Likes varchar(50)
AS
    UPDATE tbl_Person_Details
    SET Name = @Name,
        Likes = @Likes
    WHERE ID = @ID

    SELECT CAST(scope_identity() AS int)

问题:

到目前为止,我们可以看到一切都很好。但是,在调试时,我们可能会遇到多种导致问题的场景。这些如下:

  1. 在函数后面的代码中,即使有时我只想更新一个参数,我也必须声明所有参数。
  2. 如果我们添加一个名为“标题”的新列,并且前端 HTML 有一个下拉列表。我们可以通过在我们的存储过程中再添加一行和对任何函数添加一行参数来更新我们的代码。但是因为现在存储过程将有一个新参数,然后在我们没有更新“标题”的函数后面的代码中,我们将收到 SQL 异常错误,因为我们没有通过这个给定的函数将数据提供回存储过程。李>

我认为这里的设计很糟糕,但我认为唯一可能的解决方案是拥有多个存储过程,即每个函数一个。如果这是最好的方法并且它是否健壮,有什么想法吗?

如果某些列已经存在,我真正需要的是不要更新它们。例如,当我更新 Likes 时,我不想更新行的名称。

【问题讨论】:

  • 一个UPDATE操作从不插入一个新行,因此在UPDATE之后调用SCOPE_IDENTITYNOT返回任何有意义的东西。 ...(它将在此上下文中返回最后一个身份值 inserted - 但没有任何内容被 inserted......)
  • 谢谢@marc_s,如果它根本没有用,我会删除它。

标签: c# sql-server tsql stored-procedures parameters


【解决方案1】:

可以只为这两个值之一传入NULL,如果您不想更新它,然后将您的存储过程调整为:

ALTER PROCEDURE [dbo].[spUpdatePersonBasics]
    @ID int, 
    @Name varchar(50),
    @Likes varchar(50)
AS
    UPDATE tbl_Person_Details
    SET Name = ISNULL(@Name, Name)
        Likes = ISNULL(@Likes, Likes)
    WHERE ID = @ID

所以如果你传入@Name = NULL,那么UPDATE 基本上会将Name 更新为Name 的值——真的是“非更新”。

要从 C# 中传入 NULL,请使用 DBNull.Value:

comm.Parameters.Add("@Name", SqlDbType.VarChar, 50).Value = DBNull.Value;

我选择使用.Add() 方法,并且我选择为参数显式指定SqlDbType(包括长度,对于基于字符串的参数)。

如果你想传递参数 - 只需使用这个:

comm.Parameters.Add("@Name", SqlDbType.VarChar, 50).Value = tbName.Text;

由于.Text 属性已经string,因此在其上调用.ToString() 真的没有意义......

【讨论】:

  • 完美!这似乎可以满足我的需要,并且可以在多个领域中成长。请问为什么需要指定SqlDbType.VarChar, 50).Value?是必须的吗?
  • @shucode: 好吧 - 您使用的定义名称和值的调用已弃用,并且.AddWithValue 方法也存在has a few unexpected and undesirable potential side effects - 真的,最后,我对我的参数应该是非常明确感到最舒服 - 包括数据类型和字符串长度
  • 现在说得通了。谢谢你的解释和链接,我希望我能早点更新这个,但是嘿,这是我的“当日学习清单”扩展了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-07-22
  • 1970-01-01
  • 2016-04-05
  • 1970-01-01
相关资源
最近更新 更多