【问题标题】:Using numerical parameter placeholders in Dapper在 Dapper 中使用数值参数占位符
【发布时间】:2015-09-25 09:00:47
【问题描述】:

刚开始使用 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 一起工作就像轻而易举

【问题讨论】:

    标签: c# ado.net dapper


    【解决方案1】:

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

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

    将参数索引转换为属性名称的代码很简单,可以使用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));
    

    嗯...玩反射发射总是有趣,但要添加对位置参数的支持就需要做很多工作。更改 Dapper 代码可能更容易(即使该函数老实说是一团糟)。

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

    【讨论】:

    • 谢谢你的详细解释,让我看看我怎么能适应同样的东西
    猜你喜欢
    • 2015-01-15
    • 2016-10-17
    • 2023-01-13
    • 1970-01-01
    • 2017-08-07
    • 1970-01-01
    • 2022-11-24
    • 2022-01-18
    • 2016-10-01
    相关资源
    最近更新 更多