Uso de marcadores de posición de parámetros numéricos en Dapper

ado.net c# dapper

Pregunta

Acabo de empezar a trabajar con Dapper (de Nuget) y no pude entender lo siguiente:

Esto funciona:

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

Esto no funciona:

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

Así que no está ocupando los marcadores de posición numéricos, este es el comportamiento estándar o me estoy perdiendo algo. Lo mismo funciona como una brisa con PetaPoco

Respuesta aceptada

Dapper usa un objeto (no una lista) para los parámetros de consulta. Significa que no puede (confiablemente) usar índices para obtener valores de propiedad (porque, formalmente, el orden de propiedad en un objeto no está especificado).

En detalle, debe verificar el método CreateParamInfoGenerator() , el código emitido usa GetProperties() para leer todos los parámetros públicos de su objeto. No hay mucho que pueda hacer a menos que lo bifurque y lo cambie.

El código para transformar el índice de parámetro al nombre de la propiedad es sencillo, el orden de propiedad se puede lograr con el código de C # Get FieldInfos / PropertyInfos en el orden original?

Tenga en cuenta que GetProperties() no admite usos complicados (por ejemplo, implementar IDynamicMetaObjectProvider para asignar nombres de propiedad a índices, sin embargo, puede emitir su propio tipo desde una matriz de valores. Tenga en cuenta que las limitaciones de nombre de miembro se establecen por idioma, no por CLR o por CIL, entonces puede crear un tipo con propiedades cuyo nombre sea un dígito. Esto es una prueba de concepto:

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).
}

Ahora puedes usarlo así:

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

Bueno ... siempre es divertido jugar con Reflection Emit pero es mucho trabajo solo para agregar soporte para los parámetros posicionales. Puede ser más fácil cambiar el código de Dapper (incluso si esa función es, sinceramente, un gran lío enrevesado).

Como nota final ... ahora también tenemos a Roslyn, entonces podemos saber el orden en que se declaran las propiedades (y tal vez incluso más) sin embargo, hasta ahora no jugué con eso ...



Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué
Licencia bajo: CC-BY-SA with attribution
No afiliado con Stack Overflow
¿Es esto KB legal? Sí, aprende por qué