Utilisation d'espaces réservés aux paramètres numériques dans Dapper

ado.net c# dapper

Question

Je viens juste de commencer à travailler avec Dapper (de Nuget) et je n'arrivais pas à comprendre ce qui suit:

Cela marche:

_connection.Query<MySalesPerson>(@"select * from Sales.SalesPerson where territoryId = @id",
                    new {id = territory.TerritoryID});

Cela ne fonctionne pas:

_connection.Query<MySalesPerson>(@"select * from Sales.SalesPerson where territoryId = @0",
                    new {id = territory.TerritoryID});

Donc, cela ne prend pas les espaces réservés numériques, c'est le comportement standard ou je manque quelque chose. La même chose fonctionne comme une brise avec PetaPoco

Réponse acceptée

Dapper utilise un objet (pas une liste) pour les paramètres de requête. Cela signifie qu'il ne peut pas (de manière fiable) utiliser des index pour obtenir des valeurs de propriété (car, formellement, l'ordre des propriétés dans un objet n'est pas spécifié).

En détail, vous devez vérifier la méthode CreateParamInfoGenerator() , le code émis utilise GetProperties() pour lire tous les paramètres publics de votre objet. Il n'y a pas grand chose à faire à moins de le changer.

Le code pour transformer l'index de paramètre en nom de propriété est simple, le classement des propriétés peut être réalisé avec le code de C # Get FieldInfos / PropertyInfos dans l'ordre d'origine?

Notez que GetProperties() ne prend pas en charge les utilisations délicates (par exemple, implémenter IDynamicMetaObjectProvider pour mapper les noms de propriétés avec des index, mais vous pouvez émettre votre propre type à partir d'un tableau de valeurs. CLR ou par CIL alors vous pouvez créer un type avec des propriétés dont le nom est un chiffre.

object CreatePropertiesFromValues(params object[] args) {
   // Code to emit new type...

    int index = 0;
    foreach (object arg in args) {
        var name = index.ToString();
        var type = typeof(object); // We don't need strongly typed object!
        var field = typeBuilder.DefineField("_" + name, type, FieldAttributes.Private);

        var property = typeBuilder.DefineProperty(name, PropertyAttributes.HasDefault, type, null);

        var method = typeBbuilder.DefineMethod("get_" + name,
            MethodAttributes.Public | MethodAttributes.SpecialName | MethodAttributes.HideBySig,
            type, Type.EmptyTypes);

        var generator = method.GetILGenerator();
        generator.Emit(OpCodes.Ldarg_0);
        generator.Emit(OpCodes.Ldfld, field);
        generator.Emit(OpCodes.Ret);

        property.SetGetMethod(method);

        ++index;
    }

    // Code to create an instance of this new type and to set
    // property values (up to you if adding a default constructor
    // with emitted code to initialize each field or using _plain_
    // Reflection).
}

Maintenant, vous pouvez l'utiliser comme ceci:

_connection.Query<MySalesPerson>(@"select * from Sales.SalesPerson where territoryId = @0", 
    CreatePropertiesFromValues(territory.TerritoryID));

Eh bien ... c'est toujours amusant de jouer avec Reflection Emit, mais il y a beaucoup de travail à faire pour ajouter la prise en charge des paramètres de position. Il peut être plus facile de changer le code Dapper (même si, honnêtement, cette fonction est un gros désordre alambiqué).

Comme note finale ... maintenant nous avons aussi Roslyn alors nous pouvons savoir l'ordre dans lequel les propriétés sont déclarées (et peut-être même plus) mais jusqu'à présent je n'ai pas joué avec ...



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