GetItemMetadata DisplayText Without N+1 on Multiple Content Items

Topics: Customizing Orchard, Writing modules
Jan 16 at 3:55 PM
I am trying to avoid the infamous N+1 issues but cannot figure out how to do it when I want to utilize GetItemMetadata DisplayText for MULTIPLE content items (don't think there is a function that does this in batch. Here is the code I have to optimize:
return new ProductRecommendationViewModel {
    ProductRecommendations = _contentManager
        .List<ProductPart>()
        .Select(
            p => new ProductRecommendationEntry {
                ProductRecommendationId = p.ContentItem.Id,
                ProductRecommendation = p,
                IsSelected = productRecommendations.ContainsKey(p.Id) ? true : false,
                RecommendationCondition = productRecommendations.ContainsKey(p.Id) ? productRecommendations[p.Id] : RecommendationConditions.Conditions.AlwaysRecommended,
                RecommendationConditions = GetRecommendationConditions(productRecommendations.ContainsKey(p.Id) ? productRecommendations[p.Id] : RecommendationConditions.Conditions.AlwaysRecommended),
                DisplayText = _contentManager.GetItemMetadata(p).DisplayText
            }
        )
        .OrderBy(vm => vm.DisplayText)
        .ToList()
};
Note the DisplayText is calling a query for EVERY product so this will take longer and longer as I have more products. This is what I want to batch BEFORE I get into the Select area but I am not sure how it can be done. I don't want to take a dependency on TitlePart because content items don't always have TitlePart (so DisplayText seems correct, just inefficient).

Thanks for the help.
Dec 12 at 12:17 AM
Ugh, the issue has come back to haunt me. Pinging this again to see if anyone else has any ideas (other than calling on TitlePart which is what I am going to do in the interim).
Dec 12 at 12:48 AM
For anyone following along at home, I found the issue. It is an issue that I even had a pull request in on the past for. You cannot have an efficient query where you just have the Part and not the record. Here is the final (far more efficient) code:
return new ProductRecommendationViewModel {
    ProductRecommendations = _contentManager.Query<ProductPart, ProductPartRecord>()
        .List()
        .Select(
            p => new ProductRecommendationEntry {
                ProductRecommendationId = p.ContentItem.Id,
                ProductRecommendation = p,
                IsSelected = productRecommendations.ContainsKey(p.Id) ? true : false,
                RecommendationCondition = productRecommendations.ContainsKey(p.Id) ? productRecommendations[p.Id] : RecommendationConditions.Conditions.AlwaysRecommended,
                RecommendationConditions = GetRecommendationConditions(productRecommendations.ContainsKey(p.Id) ? productRecommendations[p.Id] : RecommendationConditions.Conditions.AlwaysRecommended),
                DisplayText = _contentManager.GetItemMetadata(p.ContentItem).DisplayText
            }
        )
        .OrderBy(vm => vm.DisplayText)
        .ToList()
};