From 5ad39ebcc3b5448ddcdbc3c6fdd67d94833acaae Mon Sep 17 00:00:00 2001 From: Piotr Szmyd Date: Mon, 6 Jan 2014 18:50:20 +0100 Subject: [PATCH] Support for query hints on IContentQuery. --- .../ContentManagement/DefaultContentQuery.cs | 116 ++++++++++-------- .../ContentManagement/IContentQuery.cs | 3 + 2 files changed, 69 insertions(+), 50 deletions(-) diff --git a/src/Orchard/ContentManagement/DefaultContentQuery.cs b/src/Orchard/ContentManagement/DefaultContentQuery.cs index 3b5391ee4..4a42926f9 100644 --- a/src/Orchard/ContentManagement/DefaultContentQuery.cs +++ b/src/Orchard/ContentManagement/DefaultContentQuery.cs @@ -63,7 +63,6 @@ namespace Orchard.ContentManagement { return BindCriteriaByPath(BindItemCriteria(), typeof(TRecord).Name); } - private void ForType(params string[] contentTypeNames) { if (contentTypeNames != null && contentTypeNames.Length != 0) // don't use the IN operator if not needed for performance reasons @@ -174,6 +173,57 @@ namespace Orchard.ContentManagement { return criteria.SetProjection(Projections.RowCount()).UniqueResult(); } + void WithQueryHints(QueryHints hints) { + if (hints == QueryHints.Empty) { + return; + } + + var contentItemVersionCriteria = BindItemVersionCriteria(); + var contentItemCriteria = BindItemCriteria(); + + var contentItemMetadata = _session.SessionFactory.GetClassMetadata(typeof(ContentItemRecord)); + var contentItemVersionMetadata = _session.SessionFactory.GetClassMetadata(typeof(ContentItemVersionRecord)); + + // break apart and group hints by their first segment + var hintDictionary = hints.Records + .Select(hint => new { Hint = hint, Segments = hint.Split('.') }) + .GroupBy(item => item.Segments.FirstOrDefault()) + .ToDictionary(grouping => grouping.Key, StringComparer.InvariantCultureIgnoreCase); + + // locate hints that match properties in the ContentItemVersionRecord + foreach (var hit in contentItemVersionMetadata.PropertyNames.Where(hintDictionary.ContainsKey).SelectMany(key => hintDictionary[key])) { + contentItemVersionCriteria.SetFetchMode(hit.Hint, FetchMode.Eager); + hit.Segments.Take(hit.Segments.Count() - 1).Aggregate(contentItemVersionCriteria, ExtendCriteria); + } + + // locate hints that match properties in the ContentItemRecord + foreach (var hit in contentItemMetadata.PropertyNames.Where(hintDictionary.ContainsKey).SelectMany(key => hintDictionary[key])) { + contentItemVersionCriteria.SetFetchMode("ContentItemRecord." + hit.Hint, FetchMode.Eager); + hit.Segments.Take(hit.Segments.Count() - 1).Aggregate(contentItemCriteria, ExtendCriteria); + } + + if (hintDictionary.SelectMany(x => x.Value).Any(x => x.Segments.Count() > 1)) + contentItemVersionCriteria.SetResultTransformer(new DistinctRootEntityResultTransformer()); + } + + void WithQueryHintsFor(string contentType) { + var contentItem = ContentManager.New(contentType); + var contentPartRecords = new List(); + foreach (var part in contentItem.Parts) { + var partType = part.GetType().BaseType; + if (partType.IsGenericType && partType.GetGenericTypeDefinition() == typeof(ContentPart<>)) { + var recordType = partType.GetGenericArguments().Single(); + contentPartRecords.Add(recordType.Name); + } + } + + WithQueryHints(new QueryHints().ExpandRecords(contentPartRecords)); + } + + private static ICriteria ExtendCriteria(ICriteria criteria, string segment) { + return criteria.GetCriteriaByPath(segment) ?? criteria.CreateCriteria(segment, JoinType.LeftOuterJoin); + } + IContentQuery IContentQuery.ForPart() { return new ContentQuery(this); } @@ -239,6 +289,16 @@ namespace Orchard.ContentManagement { _query.OrderByDescending(keySelector); return new ContentQuery(_query); } + + IContentQuery IContentQuery.WithQueryHints(QueryHints hints) { + _query.WithQueryHints(hints); + return this; + } + + IContentQuery IContentQuery.WithQueryHintsFor(string contentType) { + _query.WithQueryHintsFor(contentType); + return this; + } } @@ -269,58 +329,14 @@ namespace Orchard.ContentManagement { return this; } - - public IContentQuery WithQueryHints(QueryHints hints) { - if (hints == QueryHints.Empty) { - return this; - } - - var contentItemVersionCriteria = _query.BindItemVersionCriteria(); - var contentItemCriteria = _query.BindItemCriteria(); - - var contentItemMetadata = _query._session.SessionFactory.GetClassMetadata(typeof(ContentItemRecord)); - var contentItemVersionMetadata = _query._session.SessionFactory.GetClassMetadata(typeof(ContentItemVersionRecord)); - - // break apart and group hints by their first segment - var hintDictionary = hints.Records - .Select(hint => new { Hint = hint, Segments = hint.Split('.') }) - .GroupBy(item => item.Segments.FirstOrDefault()) - .ToDictionary(grouping => grouping.Key, StringComparer.InvariantCultureIgnoreCase); - - // locate hints that match properties in the ContentItemVersionRecord - foreach (var hit in contentItemVersionMetadata.PropertyNames.Where(hintDictionary.ContainsKey).SelectMany(key => hintDictionary[key])) { - contentItemVersionCriteria.SetFetchMode(hit.Hint, FetchMode.Eager); - hit.Segments.Take(hit.Segments.Count() - 1).Aggregate(contentItemVersionCriteria, ExtendCriteria); - } - - // locate hints that match properties in the ContentItemRecord - foreach (var hit in contentItemMetadata.PropertyNames.Where(hintDictionary.ContainsKey).SelectMany(key => hintDictionary[key])) { - contentItemVersionCriteria.SetFetchMode("ContentItemRecord." + hit.Hint, FetchMode.Eager); - hit.Segments.Take(hit.Segments.Count() - 1).Aggregate(contentItemCriteria, ExtendCriteria); - } - - if (hintDictionary.SelectMany(x => x.Value).Any(x => x.Segments.Count() > 1)) - contentItemVersionCriteria.SetResultTransformer(new DistinctRootEntityResultTransformer()); - + IContentQuery IContentQuery.WithQueryHints(QueryHints hints) { + _query.WithQueryHints(hints); return this; } - private static ICriteria ExtendCriteria(ICriteria criteria, string segment) { - return criteria.GetCriteriaByPath(segment) ?? criteria.CreateCriteria(segment, JoinType.LeftOuterJoin); - } - - public IContentQuery WithQueryHintsFor(string contentType) { - var contentItem = _query.ContentManager.New(contentType); - var contentPartRecords = new List(); - foreach (var part in contentItem.Parts) { - var partType = part.GetType().BaseType; - if (partType.IsGenericType && partType.GetGenericTypeDefinition() == typeof(ContentPart<>)) { - var recordType = partType.GetGenericArguments().Single(); - contentPartRecords.Add(recordType.Name); - } - } - - return WithQueryHints(new QueryHints().ExpandRecords(contentPartRecords)); + IContentQuery IContentQuery.WithQueryHintsFor(string contentType) { + _query.WithQueryHintsFor(contentType); + return this; } } } diff --git a/src/Orchard/ContentManagement/IContentQuery.cs b/src/Orchard/ContentManagement/IContentQuery.cs index affaa6715..0d6c6ad27 100644 --- a/src/Orchard/ContentManagement/IContentQuery.cs +++ b/src/Orchard/ContentManagement/IContentQuery.cs @@ -24,6 +24,9 @@ namespace Orchard.ContentManagement { IContentQuery Where(Expression> predicate) where TRecord : ContentPartRecord; IContentQuery OrderBy(Expression> keySelector) where TRecord : ContentPartRecord; IContentQuery OrderByDescending(Expression> keySelector) where TRecord : ContentPartRecord; + + IContentQuery WithQueryHints(QueryHints hints); + IContentQuery WithQueryHintsFor(string contentType); } public interface IContentQuery : IContentQuery where TPart : IContent where TRecord : ContentPartRecord {