C#中的SQL查询标量结果

4

在某些编程环境中,从 SQL 查询获取标量值很容易:

RowCount = Connection.Execute("SELECT Count(*) FROM TableA").Fields(0).Value

在C#中,如果已经打开了一个SqlConnection变量conn,是否有更简单的方法来完成相同的操作,而不必费力地创建SqlCommand、DataReader等,总共需要大约5行代码完成这项工作?
5个回答

14

SqlCommand有一个ExecuteScalar方法可以实现您需要的功能。

 cmd.CommandText = "SELECT COUNT(*) FROM dbo.region";
 Int32 count = (Int32) cmd.ExecuteScalar();

谢谢。命令对象需要特别处理Dispose或在using块内部吗? - ErikE
是的,我相信如此。SqlCommand从DbCommand获取IDisposable。 - Joe
3
我将授予你答案奖,因为你首先提供了 ExecuteScalar,虽然包括使用 using 的信息会更好。 - ErikE
ExecuteNonQuery返回受影响的行数。当您期望返回集合仅包含一个列和一行值时,最好使用ExecuteScaler。例如标识值或计数。您不需要将其转储到数据集中,然后尝试读取tables[0] rows[0] columns[0]。 - Robert Quinn

3
如果您可以使用LINQ2SQL(或EntityFramework),则可以简化实际查询的请求。
using (var context = new MyDbContext("connectionString"))
{
    var rowCount = context.TableAs.Count();
}

如果LINQ2SQL是一个选项,与手动创建所有SqlCommand等相比,它还具有许多其他好处。

2
ExecuteScalar函数,它至少可以让你免于使用DataReader
static public int AddProductCategory(string newName, string connString)
{
    Int32 newProdID = 0;
    string sql =
        "INSERT INTO Production.ProductCategory (Name) VALUES (@Name); "
        + "SELECT CAST(scope_identity() AS int)";
    using (SqlConnection conn = new SqlConnection(connString))
    {
        SqlCommand cmd = new SqlCommand(sql, conn);
        cmd.Parameters.Add("@Name", SqlDbType.VarChar);
        cmd.Parameters["@name"].Value = newName;
        try
        {
            conn.Open();
            newProdID = (Int32)cmd.ExecuteScalar();
        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
        }
    }
    return (int)newProdID;
}

(示例摘自此MSDN文档文章

1
你刚好迟到了几秒钟,所以我会标记你的名字。为什么要在“Int32”和“int”之间转换?它们不是一样的吗?为什么不只使用一个? - ErikE
谢谢,Erik。这是来自MSDN的一个例子。Int32和int是完全相同的。 - Uwe Keim

1

调查Command.ExecuteScalar:

using(var connection = new SqlConnection(myConnectionString))
{
    connection.Open();
    using(var command = connection.CreateCommand())
    {
        command.CommandType = CommandType.Text;
        command.CommandText = mySql;
        var result = (int)command.ExecuteScalar();
    }
}

如果你感觉非常懒,可以将所有内容封装在扩展方法中,就像我们所做的那样。

编辑:根据要求,这是一个扩展方法:

public static T ExecuteScalar<T> (this SqlConnection connection, string sql)
{
    if (connection == null)
    {
        throw new ArgumentNullException("connection");
    }

    if (string.IsNullOrEmpty(sql))
    {
        throw new ArgumentNullException("sql");
    }

    using(var command = connection.CreateCommand())
    {
        command.CommandText = sql;
        command.CommandType = CommandType.Text;
        return (T)command.ExecuteScalar();
    }
}

注意,此版本假定您已经正确构建了 SQL。我可能会创建一个扩展方法的单独重载,它接受两个参数:存储过程名称和列表。这样,您就可以保护自己免受不必要的 SQL 注入攻击。


你有一个扩展方法的示例可以分享吗? - Michael Minton

1

您不需要使用DataReader。此示例返回标量值:

Object result;
using (SqlConnection con = new SqlConnection(ConnectionString)) {
       con.Open();
       using (SqlCommand cmd = new SqlCommand(SQLStoredProcName, con)) {
       result = cmd.ExecuteScalar();
      }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接