无法在 Dapper 中使用多重映射
与 Dapper 一起玩,我对到目前为止的结果非常满意 - 有趣!
但现在,我的下一个场景是从两个表读取数据 - 一个 Student
和一个 Address
表。
Student
表的主键为 StudentID (INT IDENTITY)
,Address
具有 AddressID (INT IDENTITY)
。 Student
还有一个名为 AddressID
的 FK,链接到 Address
表中。
我的想法是创建两个类,每个表一个,并具有我感兴趣的属性。此外,我将 Address
类型的 PrimaryAddress
属性放入我的 Student
类。
然后,我尝试在单个查询中检索学生和地址数据 - 我模仿 Github page:
var data = connection.Query<Post, User>(sql, (post, user) => { post.Owner = user; });
var post = data.First();
这里检索一个 Post
和一个 User
,并将帖子的所有者设置为用户 - 返回的类型是一个帖子
- 正确的?
因此,在我的代码中,我为通用 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, 细绳, 系统.Func, 动态的,System.Data.IDbTransaction, 布尔值、字符串、整数?, System.Data.CommandType?)' 需要 6 类型参数
我真的不明白为什么 Dapper 坚持使用带有 6 个类型参数的重载...
Playing around with Dapper, I'm quite pleased with the results so far - intriguing!
But now, my next scenario would be to read data from two tables - a Student
and an Address
table.
Student
table has a primary key of StudentID (INT IDENTITY)
, Address
has an AddressID (INT IDENTITY)
. Student
also has an FK called AddressID
linking into the Address
table.
My idea was to create two classes, one for each table, with the properties I'm interested in. Additionally, I put an PrimaryAddress
property of type Address
onto my Student
class in C#.
I then tried to retrieve both student and address data in a single query - I mimick the sample that's given on the Github page:
var data = connection.Query<Post, User>(sql, (post, user) => { post.Owner = user; });
var post = data.First();
Here, a Post
and a User
are retrieved, and the owner of the post is set to the user - the type returned is a Post
- correct?
So in my code, I define two parameters to the generic Query
extension method - a Student
as the first which should be returned, and an Address
as the second, which will be stored onto the student instance:
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 });
Trouble is - I get an error in Visual Studio:
Using the generic method
'Dapper.SqlMapper.Query(System.Data.IDbConnection,
string,
System.Func,
dynamic, System.Data.IDbTransaction,
bool, string, int?,
System.Data.CommandType?)' requires 6
type arguments
I don't really understand why Dapper insists on using this overload with 6 type arguments...
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
那是因为我更改了 API 并忘记更新文档,我纠正了错误。
请务必查看 Tests.cs< /a> 获取完整的最新规范。
特别是,旧的 API 过去常常采用
Action
来执行映射,问题是它感觉既随意又不灵活。您无法完全控制返回类型。新的 API 采用Func
。因此,您可以控制从映射器返回的类型,并且它不需要是映射类型。我只是在多重映射方面增加了一些额外的灵活性,这个测试应该清楚地表明:
Dapper 通过单一方法管道所有多重映射 API,因此如果出现故障,它将最终出现在 6 参数中。另一个难题是我不允许一些超级灵活的分割,这是我刚刚添加的。
请注意,
splitOn
参数默认为Id
,这意味着它将采用名为id
或Id
的列作为第一个对象边界。但是,如果您需要多个具有不同名称的主键的边界(例如“3 路”多重映射),您现在可以传入逗号分隔的列表。因此,如果我们要解决上述问题,下面的方法可能会起作用:
That would be cause I changed APIs and forgot to update the documentation, I corrected the error.
Be sure to have a look at Tests.cs for a full up-to-date spec.
In particular, the old API used to take in an
Action<T,U>
to perform the mapping, the trouble was that it felt both arbitrary and inflexible. You could not fully control the return type. The new APIs take in aFunc<T,U,V>
. So you can control the type you get back from the mapper and it does not need to be a mapped type.I just tied up some additional flexibility around multi mapping, this test should make it clear:
Dapper pipes all the multi mapping APIs through a single method, so if something fails it will end up in the 6 param one. The other piece of the puzzle was that I did not allow for some super flexible splits, which I just added.
Note, the
splitOn
param will default toId
, meaning it will take a column calledid
orId
as the first object boundary. However if you need boundaries on multiple primary keys that have different names for say a "3 way" multi mapping, you can now pass in a comma separated list.So if we were to fix the above, probably the following would work: