C# 返回标识值时ExecuteScalar vs ExecuteOnQuery

C# 返回标识值时ExecuteScalar vs ExecuteOnQuery,c#,sql-server,executenonquery,executescalar,C#,Sql Server,Executenonquery,Executescalar,试图确定如果要返回新插入行的标识列,最好使用ExecuteScalar或ExecuteNonQuery。我已经阅读并理解了其中的差异,但当查看几周前我编写的一些代码(同时大量借用了本网站的内容)时,我发现在我的插入中我使用的是ExecuteScalar,如下所示: publicstaticintsavetest(testnewtest) { var conn=DbConnect.Connection(); const string sqlString=“插入dbo.Tests(测试人员,前提)”

试图确定如果要返回新插入行的标识列,最好使用
ExecuteScalar
ExecuteNonQuery
。我已经阅读并理解了其中的差异,但当查看几周前我编写的一些代码(同时大量借用了本网站的内容)时,我发现在我的插入中我使用的是
ExecuteScalar
,如下所示:

publicstaticintsavetest(testnewtest)
{
var conn=DbConnect.Connection();
const string sqlString=“插入dbo.Tests(测试人员,前提)”+
“值(@tester,@premise)”+
“SET@newId=SCOPE_IDENTITY();”;
使用(康涅狄格州)
{
使用(var cmd=new SqlCommand(sqlString,conn))
{
cmd.Parameters.AddWithValue(“@tester”,newTest.tester);
cmd.Parameters.AddWithValue(“@premise”,newTest.premise);
cmd.Parameters.Add(“@newId”,SqlDbType.Int).Direction=ParameterDirection.Output;
cmd.CommandType=CommandType.Text;
conn.Open();
cmd.ExecuteScalar();
返回(int)cmd.Parameters[“@newId”].Value;
}
}
}
这对我需要的很好,所以我想知道

  • 我是否应该在这里使用
    ExecuteNonQuery
    ,因为它“更适合”进行插入
  • 由于我使用的是输出参数,因此检索标识值的方式是否相同
  • 是否存在与这种或那种方式相关的性能影响
  • 总的来说,有没有更好的方法

  • 我使用的是Visual Studio 2010、.NET 4.0和SQL Server 2008r2,以防万一会有什么不同。

    正如Aaron所建议的,存储过程会使它更快,因为它可以节省SQL Server编译SQL批处理的工作。但是,您仍然可以使用这两种方法:
    ExecuteScalar
    ExecuteNonQuery
    。嗯,它们之间的性能差异是如此之小,以至于任何一种方法都是“合适的”

    话虽如此,如果要从输出参数获取标识值,我不认为使用
    ExecuteScalar
    有什么意义。在这种情况下,
    ExecuteScalar
    返回的值将变得无用

    我喜欢的一种方法,因为它需要更少的代码,使用
    ExecuteScalar
    而不使用输出参数:

    public static int SaveTest(Test newTest)
    {
        var conn = DbConnect.Connection();
        const string sqlString = "INSERT INTO dbo.Tests ( Tester , Premise ) " +
                                 "               VALUES ( @tester , @premise ) " +
                                 "SELECT SCOPE_IDENTITY()";
        using (conn)
        {
            using (var cmd = new SqlCommand(sqlString, conn))
            {
                cmd.Parameters.AddWithValue("@tester", newTest.tester);
                cmd.Parameters.AddWithValue("@premise", newTest.premise);
    
                cmd.CommandType = CommandType.Text;
                conn.Open();
                return (int) (decimal) cmd.ExecuteScalar();
    
            }
        }
    }
    
    快乐编程


    编辑:请注意,我们需要强制转换两次:从object到
    decimal
    ,然后到
    int
    (感谢TechTurl注意到这一点)

    (1)为什么
    ExecuteNonQuery
    更合适?(2) 您是否考虑过使用存储过程?若否,原因为何?这肯定会有助于清理你放入应用程序中的所有临时SQL—当你必须更改它时,这意味着你必须重新编译并重新部署应用程序。嗯。。。ExecuteOnQuery通常用于执行不希望返回结果的SQL。ExecuteScalar返回一个值,因此不需要传递参数。您可以将SQL的最后一部分更改为
    SELECT SCOPE_IDENTITY()
    然后使用
    返回(int)cmd.ExecuteScalar()
    我使用
    ExecuteScalar
    ,因为我使用
    SELECT SCOPE\u IDENTITY
    而没有输出参数,因此检索单个值,这是
    ExecuteScalar
    的目的。需要记住的一件重要事情是应用程序的结构、目标和最简单的方法。正如Aaron所说,您可以走存储过程路线;您甚至可以利用大型查询来提取数据并在代码中编译它们。这是一个偏好的问题。但山姆在“通用”方面是正确的。@TimSchmelter就是这样做的。我永远不会猜到整个
    数值
    的事情,尤其是因为我的标识列是
    int
    (并且它在输出参数上不进行强制转换)。我甚至找到了那个,我也遇到了铸造问题。但有时它是不需要的,不知道为什么?我也使用这种方法(ExecuteScalar,在SQL命令后附加SCOPE_标识。唯一的“问题”是,如果您使用通用插入函数的这种方法,并将一个表传递给它(gasp)没有标识驱动的主键。如果是这样,您将得到一个错误
    在VB.NET中从类型“DBNull”转换为类型“String”是无效的
    (询问我如何知道),我假设您也会得到该错误的c#等价物。