2011-05-14 37 views
16

与Dapper一起玩,我对目前为止的结果感到非常满意 - 耐人寻味!无法在Dapper中使用多重映射工作

但是现在,我的下一个场景是从两个表中读取数据 - 一个Student和一个Address表。

Student表的主键为StudentID (INT IDENTITY),AddressAddressID (INT IDENTITY)Student也有一个名为AddressID的FK链接到Address表中。

我的想法是创建两个类,每个表一个,与我感兴趣的特性。此外,我把Address类型的PrimaryAddress财产到我Student类在C#。

然后我想在一个单一的查询检索学生和地址数据 - 我模拟天生是对的Github page给出的示例:

var data = connection.Query<Post, User>(sql, (post, user) => { post.Owner = user; }); 
var post = data.First(); 

这里,PostUser检索和所有者该帖子设置为用户 - 返回的类型是Post - 正确吗?

所以,在我的代码,我定义了两个参数,通用Query扩展方法 - 一个Student作为第一个应当返还和Address为第二,这将被存储到学生实例:

var student = _conn.Query<Student, Address> 
        ("SELECT s.*, a.* FROM dbo.Student s 
         INNER JOIN dbo.Address a ON s.AddressID = a.AddressID 
         WHERE s.StudentenID = @Id", 
        (stu, adr) => { stu.PrimaryAddress = adr; }, 
        new { Id = 4711 }); 

麻烦的是 - 我得到在Visual Studio中的错误:

使用泛型方法 “Dapper.SqlMapper.Query(System.Data.IDbConnection, 串, System.Func, 动态,System.Data.IDbTransaction, 布尔,字符串,整数? System.Data.CommandType?)”要求6个 类型参数

我真的不明白为什么小巧玲珑坚持使用这种过载与6种类型的参数...

+2

我有完全一样的问题,我花了一段时间来弄清楚为什么 - 萨姆解释! – 2011-05-14 13:35:09

回答

21

这将导致我改变了API并忘记更新文档,我纠正了错误。

请务必查看Tests.cs以获取完整的最新规格。

特别是,旧的API用于执行Action<T,U>来执行映射,问题在于它感到任意和不灵活。您无法完全控制返回类型。新的API采用Func<T,U,V>。所以你可以控制你从映射器获得的类型,它不需要是映射类型。通过一个单一的方法

class Person 
{ 
    public int PersonId { get; set; } 
    public string Name { get; set; } 
} 

class Address 
{ 
    public int AddressId { get; set; } 
    public string Name { get; set; } 
    public int PersonId { get; set; } 
} 

class Extra 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

public void TestFlexibleMultiMapping() 
{ 
    var sql = 
@"select 
1 as PersonId, 'bob' as Name, 
2 as AddressId, 'abc street' as Name, 1 as PersonId, 
3 as Id, 'fred' as Name 
"; 
    var personWithAddress = connection.Query<Person, Address, Extra, Tuple<Person, Address,Extra>> 
     (sql, (p,a,e) => Tuple.Create(p, a, e), splitOn: "AddressId,Id").First(); 

    personWithAddress.Item1.PersonId.IsEqualTo(1); 
    personWithAddress.Item1.Name.IsEqualTo("bob"); 
    personWithAddress.Item2.AddressId.IsEqualTo(2); 
    personWithAddress.Item2.Name.IsEqualTo("abc street"); 
    personWithAddress.Item2.PersonId.IsEqualTo(1); 
    personWithAddress.Item3.Id.IsEqualTo(3); 
    personWithAddress.Item3.Name.IsEqualTo("fred"); 

} 

小巧玲珑的管道都多地图API,所以如果事情失败,它将在结束了:

我只是绑住周围多映射一些额外的灵活性,这个测试应该清楚6个参数之一。另一个难题是我不允许进行一些超灵活的分割,我刚刚补充说。

注意,splitOn PARAM将默认为Id,这意味着它会采取一列名为idId为第一对象边界。但是,如果您需要多个具有不同名称的主键(例如“3路”多重映射)的边界,则现在可以传递逗号分隔列表。

所以,如果我们要解决上述情况,可能是以下将工作:

var student = _conn.Query<Student,Address,Student> 
       ("SELECT s.*, a.* FROM dbo.Student s 
        INNER JOIN dbo.Address a ON s.AddressID = a.AddressID 
        WHERE s.StudentenID = @Id", 
       (stu, adr) => { stu.PrimaryAddress = adr; return stu;}, 
       new { Id = 4711 }, splitOn: "AddressID").FirstOrDefault(); 
+0

好的,谢谢 - 但我怎么能添加一些标准,如'StudentId = @ Id'(然后设置@ID = 4711')到这个多映射查询? – 2011-05-14 13:21:57

+1

@marc_s编辑在... – 2011-05-14 13:30:23

+0

@marc_s请记住,有很多可选的参数来控制像命令类型,命令超时等东西。一个非常重要的学习是“缓冲”,它允许你缓冲结果,所以你没有SqlReaders相互踩踏 – 2011-05-14 13:40:18