2011-08-24 105 views
4

我有以下查詢:實體框架,MVC 3,排序依據在LINQ到實體

model.Page = db.Pages 
    .Where(p => p.PageId == Id) 
    .Include(p => p.Series 
        .Select(c => c.Comics 
           .Select(col => col.Collection))) 
    .SingleOrDefault(); 

這個偉大的工程,但我現在需要一個被稱爲「ReadingOrder」屬性訂購漫畫。

我已經試過:

model.Page = db.Pages 
    .Where(p => p.PageId == Id) 
    .Include(p => p.Series.Select(c => c.Comics.OrderBy(o => o.ReadingOrder) 
          .Select(col => col.Collection))) 
    .SingleOrDefault(); 

但是這會導致以下錯誤:

The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties. Parameter name: path

任何想法,這個錯誤是什麼意思?

在此先感謝

編輯:

我的模型:

public class Page 
{ 
    public int PageId { get; set; } 
    public string Title { get; set; } 
    public ICollection<Series> Series { get; set; } 
} 

public class Series 
{ 
    public int SeriesId { get; set; } 
    public int PageId { get; set; } 
    public string Title { get; set; } 
    public Page Page { get; set; } 
    public ICollection<Comic> Comics { get; set; } 
} 

public class Comic 
{ 
    public int ComicId { get; set; } 
    public string Title { get; set; } 
    public int ReadingOrder { get; set; } 
    public string Subtitle { get; set; } 
    public int CollectionId { get; set; } 
    public Collection Collection { get; set; } 

} 

public class Collection 
{ 
    public int CollectionId { get; set; } 
    public string Title { get; set; } 
    public ICollection<Comic> Comics { get; set; } 
} 

回答

10

例外「。包含路徑表達式必須引用一個導航屬性...「基本上抱怨說c.Comics.OrderBy不是導航屬性。 (這是一個合理的投訴,我認爲。)

實際上,EF不支持在預先加載語句(Include)中應用排序(也是過濾)。

那麼,你可以做什麼?

選項1:

排序在內存中完成裝載實體之後:

model.Page = db.Pages 
    .Where(p => p.PageId == Id) 
    .Include(p => p.Series.Select(c => c.Comics 
          .Select(col => col.Collection))) 
    .SingleOrDefault(); 

if (model.Page != null) 
{ 
    foreach (var series in model.Page.Series) 
     series.Comics = series.Comics.OrderBy(c => c.ReadingOrder).ToList(); 
} 

醜陋,而是因爲你是由ID載入顯然只有一個Page對象很可能更快(LINQ到對象在內存中)比以下選項(如果SeriesComics集合不是特別長)。

選項2:

打破了查詢,其中混合渴望和explicite裝載部分:

model.Page = db.Pages 
    .Where(p => p.PageId == Id) 
    .Include(p => p.Series) // only Series collection is included 
    .SingleOrDefault(); 

if (model.Page != null) 
{ 
    foreach (var series in model.Page.Series) 
     db.Entry(series).Collection(s => s.Comics).Query() 
      .Include(c => c.Collection) 
      .OrderBy(c => c.ReadingOrder) 
      .Load(); // one new DB query for each series in loop 
} 

方案3:

投影?

Herehere順便說一句關於複雜的導航屬性鏈的危險。它可以加載大量的重複數據。 Include確保您只有一個DB往返,但可能以更多的傳輸數據爲代價。顯式加載有多次往返,但總數可能較少。 (我知道,我給你這個包括...選擇...選擇...選擇...鏈,但我怎麼知道你會認真對待我:)。那麼,取決於你的嵌套集合的大小,它仍然是最好的選擇。)

+0

Slauma - 你是否僱用?!!再次,非常感謝您花時間研究這一點。我現在選擇了選項1,只是爲了提高速度,但是在某些時候會考慮其他兩個選項。再次感謝! – Sniffer

+0

@Sniffer:我不會推薦你聘請你寫作的人作爲選項3帶有問號的單個單詞:)其實我不確定投影是否與這些多重嵌套集合有關。 – Slauma

0

關閉我的頭頂,未經測試:

model.Page = db.Pages 
       .Where(p => p.PageId == Id) 
       .Include(p => p.Series 
           .Select(c => c.Comics 
              .Select(col => col.Collection) 
              .OrderBy(o => o.ReadingOrder))) 
       .SingleOrDefault(); 
+0

謝謝@丹尼斯,但這是訂購集合,而不是漫畫 – Sniffer

+0

嗯,你是對的。但是,如果沒有真正看到你的模型,我不知道。抱歉。 –

+0

嗨@丹尼斯 - 好點。我已將模型添加到問題文本中。 – Sniffer