关于c#:在Dapper中使用数字参数占位符

Using numerical parameter placeholders in Dapper

刚开始使用Dapper(来自Nuget)工作,却无法找出以下内容:

这有效:

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

这不起作用:

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

因此它不占用数字占位符,这是标准行为,还是我错过了一些东西。与PetaPoco

一样轻而易举


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

详细地,您应该检查CreateParamInfoGenerator()方法,发出的代码使用GetProperties()从对象中读取所有公共参数。除非您分叉并更改它,否则您将无能为力。

将参数索引转换为属性名称的代码很简单,可以使用C#的代码以原始顺序获取FieldInfos / PropertyInfos来实现属性排序?

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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).
}

现在您可以像这样使用它:

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

好吧...与"反射发射"一起玩总是很有趣,但是要增加对位置参数的支持还需要做很多工作。更改Dapper代码可能更容易(坦白地说,即使该函数造成了很大的麻烦)。

作为最后的说明...现在我们也有了Roslyn,然后我们可能知道声明属性的顺序(甚至可能更多),但是到目前为止,我还没有使用它...