18

和 Dapper 一起玩,到目前为止我对结果非常满意 - 很有趣!

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

Student表有一个主键StudentID (INT IDENTITY)Address有一个AddressID (INT IDENTITY)Student还有一个称为AddressID链接到Address表的 FK。

我的想法是创建两个类,每个表一个,具有我感兴趣的属性。此外,我在 C# 中的类中放置了一个类型的PrimaryAddress属性。AddressStudent

然后,我尝试在单个查询中同时检索学生和地址数据——我模仿了Github 页面上给出的示例:

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

在这里,aPost和 aUser被检索,并且帖子的所有者设置为用户 - 返回的类型是 a Post- 对吗?

因此,在我的代码中,我为通用Query扩展方法定义了两个参数——aStudent作为第一个应该返回的参数,anAddress作为第二个参数,它将存储到学生实例中:

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, string, System.Func, dynamic, System.Data.IDbTransaction, bool, string, int?, System.Data.CommandType?)' 需要 6 个类型参数

我真的不明白为什么 Dapper 坚持使用这个带有 6 个类型参数的重载......

4

1 回答 1

23

那是因为我更改了 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");

}

Dapper 通过单个方法管道所有多映射 API,因此如果出现故障,它将最终出现在 6 参数中。另一个难题是我不允许一些超级灵活的拆分,我刚刚添加了这些拆分。

请注意,splitOn参数将默认为Id,这意味着它将采用名为idor的列Id作为第一个对象边界。但是,如果您需要具有不同名称的多个主键的边界来表示“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();
于 2011-05-14T12:43:46.803 回答