繁体   English   中英

如何将ExecuteScalar与存储过程一起使用?

[英]How do I use ExecuteScalar with a stored Procedure?

我正在尝试获取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。

您的代码中有几个错误:您应将其编写为:

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

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

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

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

也可以看看:

与使用CommandType.Text相比,使用CommandType.StoredProcedure有什么好处?

尽管直接指定类型并使用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/

您在C#代码中遇到了一些问题-最重要的问题可能是:

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

不要使用AddWithValue 使用Add

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

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

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的《 sp_前缀是否仍然是? ,您会看到此问题的简短答案是“是”。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM