Подтвердить что ты не робот

ExecuteScalar vs ExecuteNonQuery при возврате значения идентификатора

Попытка выяснить, лучше ли использовать 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;
        }
    }
}

Это отлично работает для того, что мне нужно, поэтому мне интересно

  • Я должен использовать ExecuteNonQuery здесь, потому что это "более правильно" для вставки?
  • Будет ли получение значения идентификатора одинаковым, так как я использую выходной параметр?
  • Есть ли какие-либо образы производительности, связанные с тем или иным способом?
  • Есть ли вообще лучший способ сделать это в целом?

Я использую Visual Studio 2010,.NET 4.0 и SQL Server 2008r2, если это имеет значение.

4b9b3361

Ответ 1

Как было предложено Aaron, хранимая процедура сделает ее более быстрой, поскольку она сохраняет Sql Server в работе по компиляции вашей SQL-партии. Тем не менее, вы все равно можете пойти с любым подходом: ExecuteScalar или ExecuteNonQuery. IMHO, разница в производительности между ними настолько мала, что любой метод является "правильным".

Сказав это, я не вижу смысла использовать 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();

        }
    }
}

Счастливое программирование!

РЕДАКТИРОВАТЬ. Обратите внимание, что нам нужно дважды отбрасывать: от объекта до decimal, а затем до int (спасибо Techturtle за это замечание).