¿Puedo usar DynamicParameters con Template y tener un parámetro de retorno en dapper?

.net c# dapper

Pregunta

El sistema en el que estoy trabajando actualmente utiliza procedimientos almacenados para todo el acceso a datos. Estoy buscando en Dapper en este momento (hasta ahora se ve muy bien) pero me preguntaba si puedo usar un objeto DynamicParameters creado utilizando una plantilla, pero convertir uno de los parámetros en un parámetro de salida. Por ejemplo:

SP:

CREATE PROCEDURE InsertPerson
  @ID int Output,
  @Name varchar(100),
  @DOB DateTime2
AS
--INSERT STATEMENT

SET @ID = SCOPE_IDENTITY()

POCO:

internal class Person
{
  public int ID { get; set; }
  public string Name { get; set; }
  public DateTime DOB { get; set; }
}

Código:

var procParams = new DynamicParameters(person);
connection.Execute("InsertPerson", procParams, commandType: CommandType.StoredProcedure);

// This is where i'm having the issue, can it be done?
person.ID = procParams.Get<int>("ID");

Actual Recibo un error porque no se encontró la clave. ¿Hay alguna manera de obtener el parámetro de salida de ID sin configurar manualmente todos los parámetros de los procesos almacenados?

Respuesta aceptada

Con un ajuste rápido, Add ahora reemplaza el valor de una plantilla, lo que permite:

public void TestProcWithOutParameter()
{
    connection.Execute(
        @"CREATE PROCEDURE #TestProcWithOutParameter
@ID int output,
@Foo varchar(100),
@Bar int
AS
SET @ID = @Bar + LEN(@Foo)");
    var obj = new
    { // this could be a Person instance etc
        ID = 0,
        Foo = "abc",
        Bar = 4
    };
    var args = new DynamicParameters(obj);
    args.Add("ID", 0, direction: ParameterDirection.Output);
    connection.Execute("#TestProcWithOutParameter", args,
                 commandType: CommandType.StoredProcedure);
    args.Get<int>("ID").IsEqualTo(7);
}

¿Eso es lo suficientemente cerca? También puede usar ParameterDirection.ReturnValue , ya sea de un valor preexistente o de un nuevo valor. Tenga en cuenta que no se actualiza directamente en la plantilla original; el valor debe obtenerse de la instancia DynamicParameters (como se muestra).


Respuesta popular

Cuando utilice el constructor para DynamicParameters para especificar un objeto de plantilla, deberá especificar que @ID es un parámetro de salida. Al principio, a través de la plantilla, se establecerá en ParameterDirection.Input . Una vez que lo agregue, se anulará para tener los valores actualizados, luego puede obtener el valor por el nombre del parámetro de la siguiente manera:

procParams.Add("@ID", dbType: DbType.Int32, direction: ParameterDirection.Output);
// ... execute ...
person.ID = procParams.Get<int>("@ID");

Logré que funcionara y usé tus clases y tu código, además de lo que mostré arriba.

EDITAR: como se discutió en los comentarios, el procedimiento almacenado no acepta más argumentos de los que ha declarado. Por lo tanto, un enfoque alternativo es abandonar el procedimiento almacenado y recurrir a algunos SQL en línea. Cuando utiliza una consulta, Dapper ignorará cualquier parámetro que le haya sido asignado y que no esté especificado en la declaración SQL. Esta es una solución para abordar este problema:

string sql = "INSERT INTO Person (Name, DOB) VALUES (@Name, @DOB) SELECT SCOPE_IDENTITY()";
decimal id = conn.Query<decimal>(sql, procParams).First();
person.ID = (int)id;

Tenga en cuenta que SCOPE_IDENTITY() devuelve un decimal, no un int.

Otra idea, que creo que no es ideal, es modificar el código Dapper y agregar un método Remove a la clase DynamicParameters para eliminar los parámetros no deseados. Sin embargo, esto no te ahorra mucho, ya que pasarás tiempo especificando qué parámetros eliminar para hacer feliz un procedimiento almacenado. Si decide implementar esto, recuerde que el caso es importante al especificar la clave para eliminar del diccionario de parameters .



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow