2016-05-31 65 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項,但無論所施加的濾波的上面是適用的。