在 Dapper 中使用数值参数占位符
Using numerical parameter placeholders in Dapper
刚开始使用 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 使用对象(而非列表)作为查询参数。这意味着它不能(可靠地)使用索引来获取 属性 值(因为,正式地,对象中的 属性 顺序未指定)。
详细来说,你应该检查 CreateParamInfoGenerator()
方法,发出的代码使用 GetProperties()
从你的对象中读取所有 public 参数。除非你分叉并改变它,否则你无能为力。
将参数索引转换为 属性 名称的代码很简单,属性 排序可以通过 C# Get FieldInfos/PropertyInfos in the original order?
中的代码实现
请注意,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));
嗯...使用 Reflection Emit 总是 有趣,但仅添加对位置参数的支持就需要大量工作。更改 Dapper 代码可能更容易(即使该功能老实说是一团糟)。
作为最后的说明...现在我们也有 Roslyn 然后我们可能知道声明属性的顺序(甚至可能更多)但是到目前为止我还没有玩过它...
刚开始使用 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 使用对象(而非列表)作为查询参数。这意味着它不能(可靠地)使用索引来获取 属性 值(因为,正式地,对象中的 属性 顺序未指定)。
详细来说,你应该检查 CreateParamInfoGenerator()
方法,发出的代码使用 GetProperties()
从你的对象中读取所有 public 参数。除非你分叉并改变它,否则你无能为力。
将参数索引转换为 属性 名称的代码很简单,属性 排序可以通过 C# Get FieldInfos/PropertyInfos in the original order?
中的代码实现请注意,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));
嗯...使用 Reflection Emit 总是 有趣,但仅添加对位置参数的支持就需要大量工作。更改 Dapper 代码可能更容易(即使该功能老实说是一团糟)。
作为最后的说明...现在我们也有 Roslyn 然后我们可能知道声明属性的顺序(甚至可能更多)但是到目前为止我还没有玩过它...