渴望加载一个字段

时间:2014-05-22 12:26:13

标签: orchardcms

使用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>());

1 个答案:

答案 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查询。