使用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 :(得分: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
,然后将Select
替换为SelectMany
。同时更改摘要模板,以便在查找相同字典后显示所有图像。
一旦我这样做,我没有选择N + 1,而是为页面上的所有图像获得了一个SQL查询。