¿Cómo crear un objeto anónimo con nombres de propiedad determinados dinámicamente?

anonymous-types c# dapper

Pregunta

Dado un conjunto de valores, me gustaría crear un objeto anónimo con propiedades basadas en estos valores. Los nombres de las propiedades serían simplemente "pN" donde N es el índice del valor en la matriz.

Por ejemplo, dado

object[] values = { 123, "foo" };

Me gustaría crear el objeto anónimo

new { p0 = 123, p1 = "foo" };

La única forma en que puedo pensar para hacer esto sería usar un switch o if encadenar hasta un número razonable de parámetros para apoyar, pero me preguntaba si había una forma más elegante de hacerlo:

object[] parameterValues = new object[] { 123, "foo" };
dynamic values = null;

switch (parameterValues.Length)
{
    case 1:
        values = new { p0 = parameterValues[0] };
        break;
    case 2:
        values = new { p0 = parameterValues[0], p1 = parameterValues[1] };      
        break;
    // etc. up to a reasonable # of parameters
}

Fondo

Tengo un conjunto existente de métodos que ejecutan sentencias SQL contra una base de datos. Los métodos suelen tomar una string para la instrucción sql y un params object[] para los parámetros, si los hay. El entendimiento es que si la consulta usa parámetros, se @p0, @p1, @p2, etc.

Ejemplo:

public int ExecuteNonQuery(string commandText, CommandType commandType, params object[] parameterValues) { .... }

que se llamaría así:

db.ExecuteNonQuery("insert into MyTable(Col1, Col2) values (@p0, @p1)", CommandType.Text, 123, "foo");

Ahora me gustaría usar Dapper dentro de esta clase para envolver y exponer el método Dapper's Query<T> , y hacerlo de una manera que sea consistente con los métodos existentes, por ejemplo algo como:

public IEnumerable<T> ExecuteQuery<T>(string commandText, CommandType commandType, params object[] parameterValues) { .... }

pero el método Dapper's Query<T> toma los valores de los parámetros en un objeto anónimo:

var dog = connection.Query<Dog>("select Age = @Age, Id = @Id", new { Age = (int?)null, Id = guid }); 

dando lugar a mi pregunta sobre la creación del objeto anónimo para pasar los parámetros a Dapper.


Agregar código usando la clase DynamicParameter según lo solicitado por @Paolo Tedesco.

string sql = "select * from Account where Id = @p0 and username = @p1";
dynamic values = new DynamicParameter(123, "test");
var accounts = SqlMapper.Query<Account>(connection, sql, values);

arroja una excepción en la línea 581 del archivo SqlMapper.cs de Dapper:

using (var reader = cmd.ExecuteReader())

y la excepción es una SqlException :

Debe declarar la variable escalar "@ p0".

y verificar la propiedad cmd.Parameters no muestra parámetros configurados para el comando.

Respuesta popular

Estás haciendo un uso indebido de Dapper, nunca deberías necesitar hacer esto, en su lugar implementas IDynamicParameters o utilizas la clase DynamicParameters extremadamente flexible.

En particular:

string sql = "select * from Account where Id = @id and username = @name";
var values = new DynamicParameters();
values.Add("id", 1);
values.Add("name", "bob");
var accounts = SqlMapper.Query<Account>(connection, sql, values);

DynamicParameters puede tomar una clase anónima en el constructor. Puede DynamicParameters utilizando el método AddDynamicParams .

Además, no existe una dependencia estricta de anon-types. Dapper permitirá tipos de hormigón como params, por ejemplo:

class Stuff
{
   public int Thing { get; set; }
}

...

cnn.Execute("select @Thing", new Stuff{Thing = 1});

Kevin tenía una pregunta similar: buscando una manera rápida y fácil de unir todas las propiedades de un POCO : DynamicParameters funciona perfectamente aquí también sin necesidad de saltar el aro mágico.



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