在Entity Framework 6.1中是否可以使用 Database.SqlQuery 命令执行包含多对多关系的查询,并将其映射回DTO(使用中间DTO) - 我知道这不能一气呵成)?这样的行动会如何表现?
此示例是我目前面临的问题的非常简化的版本。我只对使用 Database.SqlQuery 可以(不能)完成的事情感兴趣。
我知道我可以使用导航属性(使用Linq),但我正在调查一个更复杂的查询的性能。这只是我试图实现的非常简化的版本。
数据库
DTO
public class EventDto{
public int EventId {get;set;}
public string Name {get;set;}
public string Slug {get;set;}
public List<ArtistDto> Headliners {get;set;}
}
public class ArtistDto{
public int ArtistId {get;set;}
public string Name {get;set;}
public string Bio {get;set;}
}
Temp DTO
public class EventWithHeadlinersDto{
public int EventId {get;set;}
public string Name {get;set;}
public string Slug {get;set;}
public int ArtistId {get;set;}
public string Name {get;set;}
public string Bio {get;set;}
}
代码
return Context.Database.SqlQuery<EventWithHeadlinersDto>(@"
SELECT * FROM [Events] E
LEFT JOIN [Headliners] H ON E.EventId = H.EventId
LEFT JOIN [Artists] A ON H.ArtistId = A.ArtistId
WHERE E.eventid = @eventId",
new SqlParameter("eventId", eventId))
.ToListAsync();
答案 0 :(得分:2)
需要一些编码(基本上复制EF查询实现过程),但可行。
首先,应修改临时DTO以包含所有必填字段,并考虑left joins
(在需要时使用nullable
类型):
public class EventWithHeadlinersDto
{
// Event Info
public int EventId { get; set; }
public string EventName { get; set; }
public string EventSlug { get; set; }
// Artist Info
public int? ArtistId { get; set; }
public string ArtistName { get; set; }
public string ArtistBio { get; set; }
}
然后你应该确保SQL SELECT
包含所有必要的列,必要时使用别名来匹配DTO属性名称:
var sql = @"
SELECT
E.EventId, E.Name EventName, E.Slug EventSlug,
A.ArtistId, A.Name ArtistName, A.Bio ArtistBio
FROM [Events] E
LEFT JOIN [Headliners] H ON E.EventId = H.EventId
LEFT JOIN [Artists] A ON H.ArtistId = A.ArtistId
WHERE E.EventId = @eventId";
然后执行sql查询并获得结果DTO设置:
var dataSet = await query.ToListAsync();
最后将其转换为所需的格式:
var eventMap = new Dictionary<int, EventDto>();
var artistMap = new Dictionary<int, ArtistDto>();
foreach (var entry in dataSet)
{
EventDto @event;
if (!eventMap.TryGetValue(entry.EventId, out @event))
{
@event = new EventDto
{
EventId = entry.EventId,
Name = entry.EventName,
Slug = entry.EventSlug,
Headliners = new List<ArtistDto>()
};
eventMap.Add(@event.EventId, @event);
}
if (entry.ArtistId != null)
{
ArtistDto artist;
if (!artistMap.TryGetValue(entry.ArtistId.Value, out artist))
{
artist = new ArtistDto
{
ArtistId = entry.ArtistId.Value,
Name = entry.ArtistName,
Bio = entry.ArtistBio,
};
artistMap.Add(artist.ArtistId, artist);
}
@event.Headliners.Add(artist);
}
}
var resultSet = eventMap.Values.ToList();
当然,在示例案例中,结果集只包含0或1个项目,但无论应用的过滤如何,上述内容都适用。