2014-05-22 88 views
1

使用ContentManager查詢內容時,是否可以加載字段?急於加載字段

我正在使用ContentManager檢索特定內容類型的所有內容項目。內容類型上有一個MediaLibraryPickerField,當我遍歷查詢結果時,它會創建一個選擇n + 1問題。我想強制這些數據被預先加載(加入初始查詢)。這對於ContentPart來說似乎很簡單,但我無法讓它在ContentField上工作。這是可能的還是有另一種方法來避免與字段選擇n + 1問題?

這是我做過嘗試,但它並沒有影響:

var myQuery = _contentManager.Query(new[] { "MyContentType" }) 
     .WithQueryHints(new QueryHints().ExpandParts<MediaPart>()); 

我還試圖擴大紀錄:

var myQuery = _contentManager.Query(new[] { "MyContentType" }) 
     .WithQueryHints(new QueryHints().ExpandRecords<MediaPartRecord>()); 
+0

問題不在於它是一個字段(字段數據存儲在內容項目記錄本身中),而是由該字段鏈接的媒體內容項目不是原始查詢的一部分。 –

+0

@BertrandLeRoy - 有道理。有關我應該怎麼做的任何建議? – joshb

+1

並非如此,但如果您可以預先收集媒體項目的ID,那麼您可以讓GetMany將所有內容重新拼接在一起。但是,我並沒有真正想到這一點,對不起。 –

回答

3

以下是我固定的投影頁面的問題,但是相同的方法或更簡單的方法可以應用於您的案例。

在爲Content形狀投影頁面,Content-ProjectionPage.cshtml的備用模板,我做了以下,這對媒體表示,項目將在將來使用創建一個查詢:

// Pre-fetch images 
var projectionItems = ((IEnumerable<dynamic>) 
    ((IEnumerable<dynamic>)Model.Content.Items) 
    .First(i => i.Metadata.Type == "List").Items) 
    .Select(s => (ContentItem)s.ContentItem); 
var mediaLibraryFields = projectionItems 
    .SelectMany(i => i.Parts.SelectMany(p => p.Fields.Where(f => f is MediaLibraryPickerField))) 
    .Cast<MediaLibraryPickerField>(); 
var firstMediaIds = mediaLibraryFields 
    .Select(f => f.Ids.FirstOrDefault()) 
    .Where(id => id != default(int)) 
    .Distinct() 
    .ToArray(); 
var firstMedia = WorkContext.Resolve<IContentManager>() 
    .GetMany<MediaPart>(firstMediaIds, VersionOptions.Published, QueryHints.Empty); 
var mediaCache = Layout.MediaCache == null 
    ? Layout.MediaCache = new Dictionary<int, MediaPart>() 
    : (Dictionary<int, MediaPart>) Layout.MediaCache; 
foreach (var media in firstMedia) { 
    mediaCache.Add(media.Id, media); 
} 

在你的情況,因爲您可以直接訪問它們,所以無需對形狀進行復雜的挖掘以挖掘字段。我必須這樣做,因爲視圖或形狀表提供者不幸是我做這件事最容易的地方。

然後,當我想要顯示圖像時,我所要做的就是訪問我的查找並嘗試從那裏獲取它。在我的備用模板MediaLibraryPicker.Summary.cshtml,我這樣做:

var field = (MediaLibraryPickerField)Model.ContentField; 
var imageIds = field.Ids; 
if (imageIds.Any()) { 
    var cm = Model.ContentPart.ContentItem.ContentManager as IContentManager; 
    var title = cm == null || Model.ContentPart == null 
     ? "" : cm.GetItemMetadata(Model.ContentPart).DisplayText; 

    var mediaCache = Layout.MediaCache as Dictionary<int, MediaPart>; 
    var firstImage = mediaCache != null 
     ? mediaCache[imageIds.First()] 
     : cm.Get(imageIds.First()).As<MediaPart>(); 
    <div class="gallery"> 
     <a href="@Url.ItemDisplayUrl((IContent)Model.ContentPart)"><img src="@Display.ResizeMediaUrl(Path: firstImage.MediaUrl, Width: 132)" class="main" alt="@title"/></a> 
    </div> 
} 

我只是在顯示領域的第一個圖像,在這裏,但你可以改變它呢f.Ids.FirstOrDefault()。請改爲f.Ids,並用SelectMany替換Select。還要更改摘要模板,以便在同一字典中查看後顯示所有圖像。

一旦我這樣做,我沒有選擇N + 1,而是獲得頁面上所有圖像的單個SQL查詢。

+0

謝謝@Bertrand!我使用了類似的方法,運行良好。 – joshb

+0

這是查詢包含媒體選擇器字段的多個項目的絕佳選擇。這是爲了解決我的表現,感謝解決方案! –