动态功能<>对于Dapper查询图

时间:2017-09-06 19:32:30

标签: c# reflection dapper

我试图动态生成并执行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<> ***/);

所以鉴于这些类型User&amp; Address只在运行时知道,如何生成适当的委托Func<User, Address, User>以传递给map参数?

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

我看到使用反射创建Func<>的{​​{3}}假设类型已知,在我的情况下它们不是因为类型参数不同(Func&lt;,&gt; / Func&lt; ; ,,&gt; / Func&lt; ,,,&gt;等)。

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

1 个答案:

答案 0 :(得分:1)

这就像我得到的那样接近。我试图克隆Dapper repo来挖掘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");
    }
}