EjecutarScalar vs ExecuteNonQuery al devolver un valor de identidad

Tratando de averiguar si es mejor utilizar ExecuteScalar o ExecuteNonQuery si deseo devolver la columna de identidad de una fila recién insertada. He leído esta pregunta y entiendo las diferencias allí, pero cuando reviso un código que escribí hace unas semanas (mientras tomaba mucho prestado de este sitio) descubrí que en mis insertos estaba usando ExecuteScalar , así:

 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; } } } 

Esto funciona bien para lo que necesito, así que me pregunto

  1. Si debería usar ExecuteNonQuery aquí porque es “más apropiado” para hacer inserciones?
  2. ¿La recuperación del valor de identidad sería la misma, ya que estoy usando un parámetro de salida?
  3. ¿Hay éxitos de rendimiento asociados con una forma u otra?
  4. ¿Hay generalmente una mejor manera de hacer esto en general?

Estoy usando Visual Studio 2010, .NET 4.0 y SQL Server 2008r2, en caso de que haya alguna diferencia.

Según lo sugerido por Aaron, un procedimiento almacenado lo haría más rápido porque le ahorra al servidor SQL el trabajo de comstackr su lote SQL. Sin embargo, aún puedes seguir cualquiera de los enfoques: ExecuteScalar o ExecuteNonQuery . En mi humilde opinión, la diferencia de rendimiento entre ellos es tan pequeña, que cualquiera de los dos métodos es “apropiado”.

Habiendo dicho eso, no veo el sentido de usar ExecuteScalar si está tomando el valor de identidad de un parámetro de salida. En ese caso, el valor devuelto por ExecuteScalar vuelve inútil.

Un enfoque que me gusta porque requiere menos código, usa ExecuteScalar sin parámetros de salida:

 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(); } } } 

¡Feliz progtwigción!

EDITAR : Tenga en cuenta que tenemos que lanzar dos veces: de objeto a decimal , y luego a int (gracias a techturtle por notar esto).