2016-05-31 37 views
1

是否可以在Entity Framework 6.1中使用Database.SqlQuery命令来执行包含多对多关系的查询,并将其映射回DTO(使用中间DTO - 我知道这不能一次完成)?这样的行为会如何表现呢?EF 6.1 Database.SqlQuery投影到复杂类型(多对多关系)

这个例子是一个极其简化的版本我目前面临的一个问题。我只是想知道什么可以(不能)用Database.SqlQuery完成。

我知道我可以使用导航属性(使用Linq),但我正在调查更复杂的查询的性能。这只是我试图实现的一个非常简化的版本。

数据库

enter image description here

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;} 
} 

温度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

你是否想在你的SQL查询中包含'FROM Events E'? – stuartd

+0

为什么不阅读'SqlQuery'方法的Intellisense提示 - 它包含一个完整的帮助主题。 –

+0

你有没有导航属性的模型?比SqlQuery更容易(并且可维护)。 –

回答

1

需要一些编码(基本上复制所述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项,但无论所施加的滤波的上面是适用的。