和Dapper一起玩,我对目前的结果非常满意 - 很有趣!
但是现在,我的下一个场景是从两个表中读取数据 - Student
和Address
表。
Student
表的主键为StudentID (INT IDENTITY)
,Address
表示AddressID (INT IDENTITY)
。 Student
还有一个名为AddressID
的FK链接到Address
表。
我的想法是创建两个类,每个表一个,具有我感兴趣的属性。另外,我将PrimaryAddress
类型的Address
属性放到我的Student
上C#中的课程。
然后我尝试在一个查询中检索学生和地址数据 - 我模仿Github page上给出的样本:
var data = connection.Query<Post, User>(sql, (post, user) => { post.Owner = user; });
var post = data.First();
在此处,检索Post
和User
,并将帖子的所有者设置为用户 - 返回的类型为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, dynamic,System.Data.IDbTransaction, bool,string,int?, System.Data.CommandType?)'需要6 类型参数
我真的不明白为什么Dapper坚持使用这种带有6种类型参数的重载......
答案 0 :(得分:22)
那是因为我更改了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
,这意味着它会将名为id
或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();