Comment créer un objet anonyme avec des noms de propriété déterminés dynamiquement?

anonymous-types c# dapper

Question

Étant donné un tableau de valeurs, je voudrais créer un objet anonyme avec des propriétés basées sur ces valeurs. Les noms de propriété seraient simplement "pN"N est l'index de la valeur dans le tableau.

Par exemple, donné

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

Je voudrais créer l'objet anonyme

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

La seule façon que je peux penser à faire serait de d'utiliser un switch ou if la chaîne à un nombre raisonnable de paramètres pour soutenir, mais je me demandais s'il y avait une façon de faire plus élégante:

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
}

Contexte

J'ai un ensemble existant de méthodes qui exécutent des instructions SQL sur une base de données. Les méthodes prennent généralement une string pour l'instruction sql et un params object[] pour les paramètres, le cas échéant. La compréhension est que si la requête utilise des paramètres, ils seront nommés @p0, @p1, @p2, etc.

Exemple:

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

qui s'appellerait comme ceci:

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

Maintenant, je voudrais utiliser Dapper dans cette classe pour envelopper et exposer la méthode Query<T> Dapper, et le faire d'une manière compatible avec les méthodes existantes, par exemple:

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

mais la méthode Query<T> Dapper prend les valeurs de paramètre dans un objet anonyme:

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

menant à ma question sur la création de l'objet anonyme pour transmettre des paramètres à Dapper.


Ajouter du code en utilisant la classe DynamicParameter comme demandé par @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);

jette une exception à la ligne 581 du fichier SqlMapper.cs de Dapper:

using (var reader = cmd.ExecuteReader())

et l'exception est une exception SqlException :

Doit déclarer la variable scalaire "@ p0".

et la vérification de la propriété cmd.Parameters ne montre aucun paramètre configuré pour la commande.

Réponse populaire

Vous utilisez mal Dapper, vous ne devriez jamais avoir à le faire, mais implémentez IDynamicParameters ou utilisez la classe DynamicParameters extrêmement flexible.

En particulier:

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 peut prendre une classe anonyme dans le constructeur. Vous pouvez concaténer DynamicParameters à l'aide de la méthode AddDynamicParams .

De plus, il n'y a pas de dépendance stricte sur les types anonymes. Dapper autorisera les types de béton comme paramètres, par exemple:

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

...

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

Kevin avait une question similaire: rechercher un moyen rapide et facile de regrouper toutes les propriétés sur un POCO - DynamicParameters fonctionne parfaitement ici sans avoir besoin de faire un saut de magie.




Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi
Sous licence: CC-BY-SA with attribution
Non affilié à Stack Overflow
Est-ce KB légal? Oui, apprenez pourquoi