Ejecute el comando Insertar y devuelva el Id insertado en Sql

111

Estoy insertando algunos valores en una tabla SQL usando C # en MVC 4. En realidad, quiero insertar valores y devolver el 'ID' del último registro insertado. Utilizo el siguiente código.

public class MemberBasicData
{
    public int Id { get; set; }
    public string Mem_NA { get; set; }
    public string Mem_Occ { get; set; }     
}

El ID se incrementa automáticamente en la base de datos cuando se inserta.

public int CreateNewMember(string Mem_NA, string Mem_Occ )
{
    using (SqlConnection con=new SqlConnection(Config.ConnectionString))
    {
        using(SqlCommand cmd=new SqlCommand("INSERT INTO Mem_Basic(Mem_Na,Mem_Occ) VALUES(@na,@occ)",con))
        {
            cmd.Parameters.AddWithValue("@na", Mem_NA);
            cmd.Parameters.AddWithValue("@occ", Mem_Occ);
            con.Open();

            int modified = cmd.ExecuteNonQuery();

            if (con.State == System.Data.ConnectionState.Open) con.Close();
                return modified;
        }
    }
}
   

Sé que ExecuteNonQuerydenota los números que afectan a la fila. En lugar de eso, uso

int modified = (int)cmd.ExecuteScalar();

Pero no funciona. Por favor ayúdame a resolver esto. Y hay algún código como cmd.ExecuteInsertAndGetID()(que no funcione con mi código).

neel
fuente
¿A qué te refieres con InsertedID?
Soner Gönül
Puede echar un vistazo a stackoverflow.com/questions/9319532/…
Linky

Respuestas:

211

La siguiente solución funcionará con SQL Server 2005 y versiones posteriores. Puede utilizar la salida para obtener el campo obligatorio. en lugar de id, puede escribir la clave que desea devolver. Hazlo asi

PARA SQL SERVER 2005 y superior

    using(SqlCommand cmd=new SqlCommand("INSERT INTO Mem_Basic(Mem_Na,Mem_Occ) output INSERTED.ID VALUES(@na,@occ)",con))
    {
        cmd.Parameters.AddWithValue("@na", Mem_NA);
        cmd.Parameters.AddWithValue("@occ", Mem_Occ);
        con.Open();

        int modified =(int)cmd.ExecuteScalar();

        if (con.State == System.Data.ConnectionState.Open) 
            con.Close();

        return modified;
    }
}

PARA versiones anteriores

    using(SqlCommand cmd=new SqlCommand("INSERT INTO Mem_Basic(Mem_Na,Mem_Occ)  VALUES(@na,@occ);SELECT SCOPE_IDENTITY();",con))
    {
        cmd.Parameters.AddWithValue("@na", Mem_NA);
        cmd.Parameters.AddWithValue("@occ", Mem_Occ);
        con.Open();

        int modified = Convert.ToInt32(cmd.ExecuteScalar());

        if (con.State == System.Data.ConnectionState.Open) con.Close();
            return modified;
    }
}
Ehsan
fuente
1
int modificado = (int) cmd.ExecuteScalar ();
neel
10
Tenga en cuenta que el nombre de la columna debe coincidir con el nombre de la columna de identidad de la tabla. Por ejemplo, una tabla con este nombre de columna de identidad: select EmployeeId, * from EmployeesRequiere este fragmento en la declaración de inserción:output inserted.EmployeeId
joshjeppson
¿Cómo comprobaría si la consulta realmente hizo la inserción en este caso?
ATD
8
Recibí un error de transmisión no válido al intentar convertir el int modified = (int)cmd.ExecuteScalar();a un int. Tuve que usar Convert para convertirlo en un int. int modified = Convert.ToInt32(cmd.ExecuteScalar());
Baddack
la siguiente modificación funciona para mí. INSERT INTO Mem_Basic (Mem_Na, Mem_Occ) salida INSERTED.ID VALUES (??)
ABB
45

Cambie la consulta a

"INSERT INTO Mem_Basic(Mem_Na,Mem_Occ) VALUES(@na,@occ); SELECT SCOPE_IDENTITY()"

Esto devolverá la última identificación insertada que luego puede obtener con ExecuteScalar

Ken Keenan
fuente
1
esto muestra un error "InValidCast Exception was unhandled by user code"
neel
2
@neel, eso se debe a que scope_identity () devuelve un tipo de datos numérico que solo puede emitir contra el tipo de datos decimal .net. Otra forma es usar la serie de funciones Convert.To <datatype> () para evitar problemas de transmisión.
Duro
2
Esta respuesta es mejor porque no tiene que escribir la columna ID de la tabla en la que se inserta.
goamn
1
SELECT SCOPE_IDENTITY () no funciona para mí, pero la salida INSERTED.ID sí lo es.
TiggerToo
1
@TiggerToo: ¿Qué versión de SQL Server estás usando? Es posible que Microsoft finalmente haya desaprobado SCOPE_IDENTITY(). OUTPUT INSERTEDapareció en IIRC SQL Server 2008 y ha sido la forma preferida de hacerlo desde
Ken Keenan
19

Procedimiento almacenado de SQL Server:

CREATE PROCEDURE [dbo].[INS_MEM_BASIC]
    @na varchar(50),
    @occ varchar(50),
    @New_MEM_BASIC_ID int OUTPUT
AS
BEGIN
    SET NOCOUNT ON;

    INSERT INTO Mem_Basic
    VALUES (@na, @occ)

    SELECT @New_MEM_BASIC_ID = SCOPE_IDENTITY()
END

Código C #:

public int CreateNewMember(string Mem_NA, string Mem_Occ )
{
    // values 0 --> -99 are SQL reserved.
    int new_MEM_BASIC_ID = -1971;   
    SqlConnection SQLconn = new SqlConnection(Config.ConnectionString);
    SqlCommand cmd = new SqlCommand("INS_MEM_BASIC", SQLconn);

    cmd.CommandType = CommandType.StoredProcedure;

    SqlParameter outPutVal = new SqlParameter("@New_MEM_BASIC_ID", SqlDbType.Int);

    outPutVal.Direction = ParameterDirection.Output;
    cmd.Parameters.Add(outPutVal);
    cmd.Parameters.Add("@na", SqlDbType.Int).Value = Mem_NA;
    cmd.Parameters.Add("@occ", SqlDbType.Int).Value = Mem_Occ;

    SQLconn.Open();
    cmd.ExecuteNonQuery();
    SQLconn.Close();

    if (outPutVal.Value != DBNull.Value) new_MEM_BASIC_ID = Convert.ToInt32(outPutVal.Value);
        return new_MEM_BASIC_ID;
}

Espero que estos te ayuden ...

También puedes usar esto si quieres ...

public int CreateNewMember(string Mem_NA, string Mem_Occ )
{
    using (SqlConnection con=new SqlConnection(Config.ConnectionString))
    {
        int newID;
        var cmd = "INSERT INTO Mem_Basic(Mem_Na,Mem_Occ) VALUES(@na,@occ);SELECT CAST(scope_identity() AS int)";

        using(SqlCommand cmd=new SqlCommand(cmd, con))
        {
            cmd.Parameters.AddWithValue("@na", Mem_NA);
            cmd.Parameters.AddWithValue("@occ", Mem_Occ);

            con.Open();
            newID = (int)insertCommand.ExecuteScalar();

            if (con.State == System.Data.ConnectionState.Open) con.Close();
                return newID;
        }
    }
}
Humayoun Kabir
fuente
0
USE AdventureWorks2012;
GO
IF OBJECT_ID(N't6', N'U') IS NOT NULL 
    DROP TABLE t6;
GO
IF OBJECT_ID(N't7', N'U') IS NOT NULL 
    DROP TABLE t7;
GO
CREATE TABLE t6(id int IDENTITY);
CREATE TABLE t7(id int IDENTITY(100,1));
GO
CREATE TRIGGER t6ins ON t6 FOR INSERT 
AS
BEGIN
   INSERT t7 DEFAULT VALUES
END;
GO
--End of trigger definition

SELECT id FROM t6;
--IDs empty.

SELECT id FROM t7;
--ID is empty.

--Do the following in Session 1
INSERT t6 DEFAULT VALUES;
SELECT @@IDENTITY;
/*Returns the value 100. This was inserted by the trigger.*/

SELECT SCOPE_IDENTITY();
/* Returns the value 1. This was inserted by the 
INSERT statement two statements before this query.*/

SELECT IDENT_CURRENT('t7');
/* Returns value inserted into t7, that is in the trigger.*/

SELECT IDENT_CURRENT('t6');
/* Returns value inserted into t6. This was the INSERT statement four statements before this query.*/

-- Do the following in Session 2.
SELECT @@IDENTITY;
/* Returns NULL because there has been no INSERT action 
up to this point in this session.*/

SELECT SCOPE_IDENTITY();
/* Returns NULL because there has been no INSERT action 
up to this point in this scope in this session.*/

SELECT IDENT_CURRENT('t7');
/* Returns the last value inserted into t7.*/
Sasidharan
fuente
0
using(SqlCommand cmd=new SqlCommand("INSERT INTO Mem_Basic(Mem_Na,Mem_Occ) " +
    "VALUES(@na,@occ);SELECT SCOPE_IDENTITY();",con))
{
    cmd.Parameters.AddWithValue("@na", Mem_NA);
    cmd.Parameters.AddWithValue("@occ", Mem_Occ);
    con.Open();

    int modified = cmd.ExecuteNonQuery();

    if (con.State == System.Data.ConnectionState.Open) con.Close();
        return modified;
}

SCOPE_IDENTITY : devuelve el último valor de identidad insertado en una columna de identidad en el mismo ámbito. para más detalles http://technet.microsoft.com/en-us/library/ms190315.aspx

Ajay
fuente
3
Sería bueno, pero ExecuteNonQuery solo devuelve el número de filas afectadas, no el ID. Use ExecuteScalar en lugar de docs.microsoft.com/en-us/dotnet/api/…
Brandtware