在Dapper中使用数值参数占位符

本文关键字:值参 参数 占位符 Dapper | 更新日期: 2023-09-27 18:14:27

刚开始使用Dapper(来自Nuget),无法理解以下内容:

如此:

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

这行不通:

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

所以它没有占用数字占位符,这是标准行为还是我错过了什么。同样的工作像PetaPoco的微风

在Dapper中使用数值参数占位符

Dapper使用对象(而不是列表)作为查询参数。这意味着它不能(可靠地)使用索引来获取属性值(因为,在形式上,对象中的属性顺序是未指定的)。

详细地说,你应该检查CreateParamInfoGenerator()方法,发出的代码使用GetProperties()从你的对象中读取所有公共参数。你能做的不多,除非你分叉并修改它。

将参数索引转换为属性名称的代码很简单,属性排序可以通过c#中的代码来实现,获取FieldInfos/propertyinfo的原始顺序?

注意GetProperties()不支持棘手的用法(例如实现IDynamicMetaObjectProvider将属性名称映射到索引),但是您可以从值数组中发出自己的类型。请注意,成员名限制是由语言设置的,而不是由CLR或CIL设置的,因此您可以创建具有名称为数字的属性的类型。这是一个概念证明:

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

现在你可以这样使用:

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

嗯…使用反射发射总是很有趣的,但是仅仅增加对位置参数的支持需要做很多工作。更改Dapper代码可能更容易(即使那个函数,老实说,是一个大的令人费解的混乱)。

最后一点…现在我们还有Roslyn那么我们可能知道属性声明的顺序(甚至更多)但是到目前为止我还没有使用它。