【问题标题】:How do I use ExecuteScalar with a stored Procedure?如何将 ExecuteScalar 与存储过程一起使用?
【发布时间】:2018-12-13 08:10:33
【问题描述】:

我正在尝试获取 Sql 数据库中的列记录计数并将结果显示在 MessageBox 中。

这是我的代码:

public DataTable CheckIfNameExist(string name)
{
    con = Connect();
    cmd = new SqlCommand();
    cmd.Connection = con;
    cmd.CommandText = "spCheckIfNameExist";
    cmd.Parameters.AddWithValue("@Name", SqlDbType.NVarChar).Value = name;
    MessageBox.Show(name);

    Int32 totalNames = (Int32) cmd.ExecuteScalar();
    string tNames = totalNames.ToString();

    MessageBox.Show(tNames);
}

这是我的 sp:

@Name nvarchar(50) = null
As
Begin
SELECT COUNT(*) from OrdersSent where CustomerName LIKE @Name + '%'
End

问题:

它总是返回 0。

【问题讨论】:

  • 您在LIKE 中使用参数的方式不正确......这就是查询本身返回0 结果的原因。 check this
  • 尝试在 cmd.executeScalar() 之前添加 cmd.CommandType=CommandType.Procedure
  • @Arjun 它是 CommandType.StoredProcedure 但我怀疑这里还有其他东西,因为错误应该导致异常
  • @Steve,我只是给他一个想法.. 是的,我也在想同样的事情.. 但是为什么在这种情况下代码没有引发异常,而是给他 0 结果

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


【解决方案1】:

您的代码中有几个错误: 你应该写成:

cmd.CommandText = "spCheckIfNameExist";
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.Add("@Name", SqlDbType.NVarChar).Value = name;

首先您需要告诉 ADO 引擎您正在调用存储过程而不是简单的命令文本,但您还需要使用 Add 而不是 AddWithValue 来准确了解传递给 SP 的参数类型。您的代码创建一个参数 int 因为 AddWithValue 的第二个参数是参数的值而不是类型。

【讨论】:

    【解决方案2】:

    您在 c# 代码中存在一些问题 - 最重要的可能是:

    cmd.Parameters.AddWithValue("@Name", SqlDbType.NVarChar).Value = name;
    

    Don't use AddWithValue. 使用Add。

    另外,您没有指定命令类型 - 默认为 Text。
    而且您正在使用SqlConnection 和SqlCommand 的字段 - 这也是错误的做法。您应该在使用它们的每个方法中创建和处置它们。

    您的代码的更好版本是这样的:

    using(var con = new SqlConnection(ConnectionString))
    {
        using(var cmd = new SqlCommand("spCheckIfNameExist", con))
        {
            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.Add("@Name", SqlDbType.NVarChar).Value = name;
            con.Open();
            var tNames = cmd.ExecuteScalar().ToString();
        }
    }
    

    让我感到困惑的另一件事是为什么名为CheckIfNameExist 的方法返回DataTable。我希望它只返回一个bool。

    如果您真的只想检查名称是否存在,您可以在 SQL 级别和 c# 级别都做得更好。

    更好的 SQL 应该是这样的:

    SELECT CAST(CASE WHEN EXISTS(
        SELECT 1 
        FROM OrdersSent 
        WHERE CustomerName LIKE @Name + '%'
    ) THEN 1 ELSE 0 END AS bit)
    

    而在c#层面,bit直接转化为bool,所以代码可以很简单:

    public bool CheckIfNameExist(string name)
    {
        using(var con = new SqlConnection(ConnectionString))
        {
            using(var cmd = new SqlCommand("spCheckIfNameExist", con))
            {
                cmd.CommandType = CommandType.StoredProcedure;
                cmd.Parameters.Add("@Name", SqlDbType.NVarChar).Value = name;
                con.Open();
                return (bool)cmd.ExecuteScalar();
            }
        }
    }
    

    还有一点需要注意 - 您应该避免在存储过程中使用 sp 前缀。
    Microsoft 已为内置系统过程保留此前缀。 如需更多信息,请阅读 Aaron Bertrand 的 Is the sp_ prefix still a no-no?,您会看到该问题的简短回答是“是”。

    sp_ 前缀并不意味着您认为它的含义:大多数人认为 sp 代表“存储过程”,而实际上它的意思是“特殊”。存储在 master 中的带有 sp_ 前缀的存储过程(以及表和视图)可以从任何数据库访问,而无需适当的引用(假设本地版本不存在)。如果该过程被标记为系统对象(使用 sp_MS_marksystemobject(将 is_ms_shipped 设置为 1 的未记录且不受支持的系统过程),则 master 中的过程将在调用数据库的上下文中执行。

    【讨论】:

    • 返回 DataTable 的原因是我有一个 If 语句,它取决于 ExecuteScalar 的结果,最终将返回 DataTable。感谢您提供非常有用的答案!
    【解决方案3】:

    您需要像这样指定命令的类型:

    cmd.CommandText = "spCheckIfNameExist";
    cmd.CommandType = CommandType.StoredProcedure;
    

    另见:

    What is the benefit of using CommandType.StoredProcedure versus using CommandType.Text?

    虽然直接指定类型,使用Value属性比AddWithValue好:

    cmd.Parameters.Add("@Name", SqlDbType.NVarChar).Value = name;
    

    以下文章也可能很有趣:

    https://blogs.msmvps.com/jcoehoorn/blog/2014/05/12/can-we-stop-using-addwithvalue-already/

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-05-20
      • 1970-01-01
      • 2012-12-01
      • 1970-01-01
      • 2010-12-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多