É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"
où 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.
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.