【问题标题】:Dynamic Func<> for Dapper query mapDapper 查询映射的 Dynamic Func<>
【发布时间】:2018-02-15 09:43:20
【问题描述】:

我正在尝试为Dapper 动态生成和执行 sql,目的是简单地传入一个类型,然后动态生成和执行 sql。

示例类:

public class User
{
    [Key]
    public int UserId { get; set; }
    public Address Address { get; set; }
}
public class Address
{
    [Key]
    public int UserId { get; set; }
    public string PostCode { get; set; }
}

将有效地运行以下内容:

// sql: "SELECT User.UserId, Address.UserId, Address.PostCode FROM User LEFT JOIN Address ON Address.User = User.UserId"... // auto generated from 'User' type including join to 'Address';

connection.Query<User, Address, User>(sql, /*** map argument needs to be dynamic Func<> ***/);

因此,鉴于这些类型 UserAddress 仅在运行时已知,我如何生成适当的委托 Func&lt;User, Address, User&gt; 以传递给 map 参数?

Func<User, Address, User> map = (u, a) => {
    u.Address = a;
    return u;
}

我看到使用反射创建Func&lt;&gt;examples 假设类型是已知的,在我的情况下它们不是,因此类型参数会有所不同(Func / Func / Func 等)。

任何帮助表示赞赏。我将继续研究使用表达式的示例,看看是否有任何问题。

【问题讨论】:

标签: c# reflection dapper


【解决方案1】:

这是我得到的最接近的结果。我试图克隆 Dapper 存储库以深入了解 Query() 方法的工作原理,但我使用的是旧版本的 Visual Studio。

public static class DynamicFuncHelper
{
    public static Delegate CreateFunc(Type type1, Type type2)
    {
        Type funcType = typeof(Func<,,>).MakeGenericType(type1, type2, type1);
        MethodInfo method =
            typeof(DynamicFuncHelper<,>)
            .MakeGenericType(type1, type2)
            .GetMethod("SetAddressProperty",
                BindingFlags.Public | BindingFlags.Static
            );
        return Delegate.CreateDelegate(funcType, method);
    }
}

public static class DynamicFuncHelper<T,U> 
    where T : class 
    where U : class
{
    public static T SetAddressProperty(T obj1, U obj2)
    {
        obj1.GetType().InvokeMember("Address",
            BindingFlags.Instance | BindingFlags.Public | BindingFlags.SetProperty,
            Type.DefaultBinder, obj1, new[] { obj2 });
        return obj1;
    }
}

通过了这个单元测试

[TestClass]
public class DynamicFuncTest
{
    [TestMethod]
    public void TestDynamicMapper()
    {
        var actualUser = new User { UserId = 1 };
        var actualAddress = new Address { PostCode = "12345", UserId = 1 };
        var testSetAddress = DynamicFuncHelper.CreateFunc(typeof(User), typeof(Address));
        var delegateResult = testSetAddress.DynamicInvoke(actualUser, actualAddress);
        Assert.AreEqual(actualUser, delegateResult, "Delegate result was not actualUser");
        Assert.AreEqual(actualAddress, actualUser.Address, "User address was not expected address");
    }
}

【讨论】:

  • 您好,谢谢您的回复。这看起来很有希望,但我仍然坚持Func 可能有任意数量的类型参数这一事实。我发现 this library 似乎可以解决问题 - 我可能只是最终将其拉入解决 map 参数。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多