C# 返回标识值时的 ExecuteScalar 与 ExecuteNonQuery

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14246744/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 11:09:08  来源:igfitidea点击:

ExecuteScalar vs ExecuteNonQuery when returning an identity value

c#sql-serverexecutenonqueryexecutescalar

提问by techturtle

Trying to figure out if it's best to use ExecuteScalaror ExecuteNonQueryif I want to return the identity column of a newly inserted row. I have read this questionand I understand the differences there, but when looking over some code I wrote a few weeks ago (whilst heavily borrowing from this site) I found that in my inserts I was using ExecuteScalar, like so:

试图弄清楚是否最好使用,ExecuteScalar或者ExecuteNonQuery我是否想返回新插入行的标识列。我已经阅读了这个问题并且我了解那里的差异,但是在查看我几周前编写的一些代码时(同时大量从该站点借用),我发现在我使用的插入中ExecuteScalar,如下所示:

public static int SaveTest(Test newTest)
{
    var conn = DbConnect.Connection();
    const string sqlString = "INSERT INTO dbo.Tests ( Tester , Premise ) " +
                             "               VALUES ( @tester , @premise ) " +
                             "SET @newId = SCOPE_IDENTITY(); ";
    using (conn)
    {
        using (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();

            return (int) cmd.Parameters["@newId"].Value;
        }
    }
}

This works fine for what I need, so I'm wondering

这对我需要的东西很好用,所以我想知道

  1. Whether I should be using ExecuteNonQueryhere because it is "more proper" for doing inserts?
  2. Would retrieving the identity value be the same either way since I'm using an output parameter?
  3. Are there any performance hits associated with one way or the other?
  4. Is there generally a better way to do this overall?
  1. 我是否应该在ExecuteNonQuery这里使用,因为它“更适合”进行插入?
  2. 由于我使用的是输出参数,因此检索身份值是否相同?
  3. 是否有任何与一种方式或另一种方式相关的性能影响?
  4. 通常有更好的方法来做到这一点吗?

I'm using Visual Studio 2010, .NET 4.0, and SQL Server 2008r2, in case that makes any difference.

我使用的是 Visual Studio 2010、.NET 4.0 和 SQL Server 2008r2,以防万一。

采纳答案by Diego

As suggested by Aaron, a stored procedure would make it faster because it saves Sql Server the work of compiling your SQL batch. However, you could still go with either approach: ExecuteScalaror ExecuteNonQuery. IMHO, the performance difference between them is so small, that either method is just as "proper".

正如 Aaron 所建议的那样,存储过程会使其更快,因为它可以节省 Sql Server 编译 SQL 批处理的工作。但是,您仍然可以使用任何一种方法:ExecuteScalarExecuteNonQuery。恕我直言,它们之间的性能差异是如此之小,以至于任何一种方法都是“正确的”。

Having said that, I don't see the point of using ExecuteScalarif you are grabbing the identity value from an output parameter. In that case, the value returned by ExecuteScalarbecomes useless.

话虽如此,ExecuteScalar如果您从输出参数中获取标识值,我看不出使用的意义。在这种情况下,返回的值ExecuteScalar变得无用。

An approach that I like because it requires less code, uses ExecuteScalarwithout output parameters:

我喜欢的一种方法,因为它需要更少的代码,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();

        }
    }
}

Happy programming!

编程快乐!

EDIT: Note that we need to cast twice: from object to decimal, and then to int(thanks to techturtle for noting this).

编辑:请注意,我们需要投射两次:从 object 到decimal,然后到int(感谢 techturtle 注意到这一点)。