如何使用 dapper 在一次查询中选择所有 SpaceShips
及其 Sightings
?
我有以下对象:
public class SpaceShip
{
public int Id { get; set; }
public string DriveType { get; set; }
public List<Sighting> Sightings { get; set; }
}
public class Sighting
{
public int Id { get; set; }
public double Lat { get; set; }
public double Lon { get; set; }
}
具有以下架构:
If Exists(Select * from sysobjects where name = 'Sightings')
Drop Table Sightings
If Exists(Select * from sysobjects where name = 'SpaceShips')
Drop Table SpaceShips
CREATE TABLE [dbo].[SpaceShips](
[Id] [int] IDENTITY(1,1) NOT NULL,
[DriveType] [varchar](max) NOT NULL,
CONSTRAINT [PK_SpaceShips] PRIMARY KEY CLUSTERED
([Id] ASC) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]
GO
CREATE TABLE [dbo].[Sightings](
[Id] [int] IDENTITY(1,1) NOT NULL,
[SpaceShipId] [int] NOT NULL,
[Lat] [decimal](18, 0) NOT NULL,
[Lon] [decimal](18, 0) NOT NULL,
CONSTRAINT [PK_Sightings] PRIMARY KEY CLUSTERED
([Id] ASC) WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]) ON [PRIMARY]
GO
ALTER TABLE [dbo].[Sightings] WITH CHECK ADD CONSTRAINT [FK_Sightings_SpaceShips] FOREIGN KEY([SpaceShipId]) REFERENCES [dbo].[SpaceShips] ([Id])
GO
ALTER TABLE [dbo].[Sightings] CHECK CONSTRAINT [FK_Sightings_SpaceShips]
GO
Insert into SpaceShips (DriveType) Values ('X18-9'),('PV-276M')
Insert into Sightings (SpaceShipId, Lat, Lon) Values (1, 10, 90), (1, 20, 80), (1, 30, 70), (1, 40, 60)
Insert into Sightings (SpaceShipId, Lat, Lon) Values (2, 104, 64), (2, 105, 63), (2, 106, 62), (2, 107, 61)
我正在尝试使用 dapper 选择 SpaceShip
列表,包括它们相关的 Sightings
,如下所示:
using (var con = MuzakiFactory.OpenPortal())
{
try
{
var sql = @"Select * From SpaceShips ship left join Sightings s on s.SpaceShipId = ship.id";
var result = con.Query<SpaceShip, List<Sighting>, SpaceShip>
(sql, (ship, sightings) => {
ship.Sightings = sightings;
return ship;
});
return result;
}
catch (Exception ex)
{
Captains.Log(ex);
throw;
}
}
但结果是 SpaceShips
列表,其中 Sightings
为空。
更新
使用 Marc 关于 QueryMultiple
的建议并自己连接似乎更容易。为了完成这项工作,我必须将 public int SpaceShipId {get;set;}
添加到我的 Sighting
类中。我最终得到了这个:
var sql = @"Select * From SpaceShips; Select * from Sightings;";
using (var multi = con.QueryMultiple(sql))
{
var ships = multi.Read<SpaceShip>().ToList();
var sightings = multi.Read<Sighting>().ToList();
foreach(var ship in ships)
{
ship.Sightings = new List<Sighting>(sightings.Where(x => x.SpaceShipId == ship.Id));
}
return ships;
}
注意:您显然希望在每个查询的 where 子句中包含父 ID。
最佳答案
首先,您必须使用 <SpaceShip, Sighting, SpaceShip>
,并编写您自己的身份管理器(阅读:字典)以使重复的数据唯一。伪代码:
(ship, sighting) => {
SpaceShip actualShip;
if(!ships.TryGetValue(ship.Id, out actualShip)) {
ships.Add(ship.Id, actualShip = ship);
}
actualShip.Sightings.Add(sighting);
return actualShip;
}
哪里ships
是 Dictionary<int, SpaceShip>
或类似的。如果您认为这是常见情况,我们当然可以考虑将其作为内置选项。
但是!这可能需要很多额外的列。就我个人而言,我很想在这里考虑使用 QueryMultiple
的多结果查询。并将两者结合起来作为后处理。
关于c# - 如何使用 dapper 返回包含其他类型列表的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10322882/