c# - sirve - ¿Cómo insertar un registro y devolver el ID recién creado con un solo SqlCommand?
return identity after sql insert c# (9)
Agregue la siguiente línea al final de la consulta SQL ...
SELECT SCOPE_IDENTITY()
Y luego use el método ExecuteScalar en el objeto SqlCommand ...
var rowCount = command.ExecuteScalar()
Estoy usando un objeto SqlCommand para insertar un registro en una tabla con una clave primaria autogenerada. ¿Cómo puedo escribir el texto de comando para que obtenga el ID recién creado cuando uso el método ExecuteScalar ()?
Directamente del Whirlpool :
Si está utilizando MS SQL, puede usar "SELECCIONAR @@ IDENTIDAD como valor" después de su inserción para obtener la última ID generada
y:
@@IDENTITY
ySCOPE_IDENTITY
devuelven el último valor de identidad generado en cualquier tabla en la sesión actual. Sin embargo,SCOPE_IDENTITY
devuelve el valor solo dentro del alcance actual;@@IDENTITY
no está limitado a un alcance específico.
Editar: Como se señaló en los comentarios, siempre debe usar SCOPE_IDENTITY
, no @@IDENTITY
.
No use @@ IDENTITY, por simple que parezca. Puede devolver valores incorrectos.
SELECT SCOPE_IDENTITY()
parece ser la elección obvia.
Agregue un parámetro de salida al objeto de comando y luego establezca el valor en la nueva ID en el procedimiento almacenado.
Procedimiento almacenado:
@ID AS INT OUTPUT
[Insert Command]
SET @ID = SCOPE_IDENTITY()
.RED:
cmd.CommandText = "stored_procedure";
SqlParameter pID = new SqlParameter("ID", DBType.Int32, 4);
pID.Direction = ParameterDirection.Output;
cmd.ExecuteScalar();
int id = Convert.ToInt32(cmd.Parameters["ID"].Value.ToString());
Inmediatamente después de su inserción, use
SELECT CAST(scope_identity() AS bigint) ---- incase you have a return result as int64
Esto devolverá la columna creada id / identity.
INSERT INTO YourTable(val1, val2, val3 ...)
VALUES(@val1, @val2, @val3...);
SELECT SCOPE_IDENTITY();
No olvides los puntos y comas al final de cada declaración.
insert into Yourtable()
values()
SELECT SCOPE_IDENTITY()
Acabo de ejecutar una prueba y verifiqué que los puntos y comas son opcionales usando SQL Server 2005 SP2 y .Net 3.5
Si su ID es un Guid, entonces encontré esta solución como la mejor:
INSERT INTO YourTable (val1, val2, val3)
OUTPUT inserted.id
VALUES (@val1, @val2, @val3)
Gracias @Scott Ivey
Demostración completa:
internal static Guid InsertNote(Note note)
{
Guid id;
using (
var connection =
new SqlConnection(ConfigurationManager.ConnectionStrings["dbconn"].ConnectionString))
{
connection.Open();
using (
var command =
new SqlCommand(
"INSERT INTO Notes ([Title],[Text]) " +
"OUTPUT inserted.id " +
$"VALUES (''{title}'',''{text}'');", connection))
{
command.CommandType = CommandType.Text;
var reader = command.ExecuteReader();
reader.Read();
id = reader.GetGuid(reader.GetOrdinal("id"));
}
connection.Close();
}
return id;
}
Recomendaría usar un Procedimiento almacenado, pero esto es para probar nuestras unidades en nuestro repositorio.
Aunque me gusta la respuesta de Dave Markle (y veo que también lo hizo, ya que la marcó como su respuesta), ese método puede fallar si tiene activadores en su base de datos, que auditan las operaciones CUD y su tabla de auditoría tiene una columna IDENTIDAD. Devolvería el valor de la identidad de la tabla de auditoría, no la tabla en la que acaba de insertar, ya que la tabla de auditoría se realizó después.
En ese caso, se puede usar un método más genérico que funcionará en ambos casos, independientemente de cualquier auditoría. Es un poco más prolijo, pero obtienes lo que pagas.
ejemplo:
@"DECLARE @tmp AS TABLE ( id int )
INSERT INTO case
(
caseID,
partID,
serialNumber,
hardware,
software,
firmware
)
OUTPUT Inserted.ID into @tmp
VALUES
(
@caseID,
@partItemID,
@serialNumber,
@hardware,
@software,
@firmware
)
Select ID from @tmp" )