Adding Query Hints and GetMany in Content Manager

--HG--
branch : 1.x
This commit is contained in:
Sebastien Ros
2011-08-24 15:24:27 -07:00
parent a09381d540
commit d0f11de6e2
4 changed files with 295 additions and 10 deletions

View File

@@ -5,12 +5,17 @@ using System.Linq;
using System.Runtime.CompilerServices;
using System.Xml.Linq;
using Autofac;
using NHibernate;
using NHibernate.Criterion;
using NHibernate.Metadata;
using NHibernate.SqlCommand;
using Orchard.ContentManagement.Handlers;
using Orchard.ContentManagement.MetaData;
using Orchard.ContentManagement.MetaData.Builders;
using Orchard.ContentManagement.MetaData.Models;
using Orchard.ContentManagement.Records;
using Orchard.Data;
using Orchard.Environment;
using Orchard.Indexing;
using Orchard.Logging;
using Orchard.UI;
@@ -24,6 +29,7 @@ namespace Orchard.ContentManagement {
private readonly IContentDefinitionManager _contentDefinitionManager;
private readonly Func<IContentManagerSession> _contentManagerSession;
private readonly Lazy<IContentDisplay> _contentDisplay;
private readonly Work<ISessionLocator> _sessionLocator;
private const string Published = "Published";
private const string Draft = "Draft";
@@ -34,7 +40,8 @@ namespace Orchard.ContentManagement {
IRepository<ContentItemVersionRecord> contentItemVersionRepository,
IContentDefinitionManager contentDefinitionManager,
Func<IContentManagerSession> contentManagerSession,
Lazy<IContentDisplay> contentDisplay) {
Lazy<IContentDisplay> contentDisplay,
Work<ISessionLocator> sessionLocator) {
_context = context;
_contentTypeRepository = contentTypeRepository;
_contentItemRepository = contentItemRepository;
@@ -42,6 +49,7 @@ namespace Orchard.ContentManagement {
_contentDefinitionManager = contentDefinitionManager;
_contentManagerSession = contentManagerSession;
_contentDisplay = contentDisplay;
_sessionLocator = sessionLocator;
Logger = NullLogger.Instance;
}
@@ -50,8 +58,10 @@ namespace Orchard.ContentManagement {
private IEnumerable<IContentHandler> _handlers;
public IEnumerable<IContentHandler> Handlers {
get {
if (_handlers == null)
if (_handlers == null) {
_handlers = _context.Resolve<IEnumerable<IContentHandler>>();
}
return _handlers;
}
}
@@ -110,8 +120,9 @@ namespace Orchard.ContentManagement {
// obtain the root records based on version options
if (options.VersionRecordId != 0) {
// short-circuit if item held in session
if (session.RecallVersionRecordId(options.VersionRecordId, out contentItem))
if (session.RecallVersionRecordId(options.VersionRecordId, out contentItem)) {
return contentItem;
}
// locate explicit version record
versionRecord = _contentItemVersionRepository.Get(options.VersionRecordId);
@@ -160,25 +171,25 @@ namespace Orchard.ContentManagement {
private ContentItemVersionRecord GetVersionRecord(VersionOptions options, ContentItemRecord itemRecord) {
if (options.IsPublished) {
return itemRecord.Versions.FirstOrDefault(
x => x.Published) ??
x => x.Published) ??
_contentItemVersionRepository.Get(
x => x.ContentItemRecord == itemRecord && x.Published);
}
if (options.IsLatest || options.IsDraftRequired) {
return itemRecord.Versions.FirstOrDefault(
x => x.Latest) ??
x => x.Latest) ??
_contentItemVersionRepository.Get(
x => x.ContentItemRecord == itemRecord && x.Latest);
}
if (options.IsDraft) {
return itemRecord.Versions.FirstOrDefault(
x => x.Latest && !x.Published) ??
x => x.Latest && !x.Published) ??
_contentItemVersionRepository.Get(
x => x.ContentItemRecord == itemRecord && x.Latest && !x.Published);
}
if (options.VersionNumber != 0) {
return itemRecord.Versions.FirstOrDefault(
x => x.Number == options.VersionNumber) ??
x => x.Number == options.VersionNumber) ??
_contentItemVersionRepository.Get(
x => x.ContentItemRecord == itemRecord && x.Number == options.VersionNumber);
}
@@ -192,6 +203,71 @@ namespace Orchard.ContentManagement {
.Select(x => Get(x.ContentItemRecord.Id, VersionOptions.VersionRecord(x.Id)));
}
public IEnumerable<T> GetMany<T>(IEnumerable<int> ids, VersionOptions options, QueryHints hints) where T : class, IContent {
var contentItemVersionRecords = GetManyImplementation(hints, (contentItemCriteria, contentItemVersionCriteria) => {
contentItemCriteria.Add(Restrictions.In("Id", ids.ToArray()));
if (options.IsPublished) {
contentItemVersionCriteria.Add(Restrictions.Eq("Published", true));
}
else if (options.IsLatest) {
contentItemVersionCriteria.Add(Restrictions.Eq("Latest", true));
}
else if (options.IsDraft) {
contentItemVersionCriteria.Add(
Restrictions.And(Restrictions.Eq("Published", false),
Restrictions.Eq("Latest", true)));
}
});
var itemsById = contentItemVersionRecords
.Select(r => Get(r.ContentItemRecord.Id, VersionOptions.VersionRecord(r.Id)))
.GroupBy(ci => ci.Id)
.ToDictionary(g => g.Key);
return ids.SelectMany(id => {
IGrouping<int, ContentItem> values;
return itemsById.TryGetValue(id, out values) ? values : Enumerable.Empty<ContentItem>();
}).AsPart<T>().ToArray();
}
public IEnumerable<T> GetManyByVersionId<T>(IEnumerable<int> versionRecordIds, QueryHints hints) where T : class, IContent {
var contentItemVersionRecords = GetManyImplementation(hints, (contentItemCriteria, contentItemVersionCriteria) =>
contentItemVersionCriteria.Add(Restrictions.In("Id", versionRecordIds.ToArray())));
var itemsById = contentItemVersionRecords
.Select(r => Get(r.ContentItemRecord.Id, VersionOptions.VersionRecord(r.Id)))
.GroupBy(ci => ci.VersionRecord.Id)
.ToDictionary(g => g.Key);
return versionRecordIds.SelectMany(id => {
IGrouping<int, ContentItem> values;
return itemsById.TryGetValue(id, out values) ? values : Enumerable.Empty<ContentItem>();
}).AsPart<T>().ToArray();
}
private IEnumerable<ContentItemVersionRecord> GetManyImplementation(QueryHints hints, Action<ICriteria, ICriteria> predicate) {
var session = _sessionLocator.Value.For(typeof (ContentItemRecord));
var contentItemVersionCriteria = session.CreateCriteria(typeof (ContentItemVersionRecord));
var contentItemCriteria = contentItemVersionCriteria.CreateCriteria("ContentItemRecord");
predicate(contentItemCriteria, contentItemVersionCriteria);
var hintDictionary = hints.Records.Distinct().ToDictionary(value => value);
var contentItemMetadata = session.SessionFactory.GetClassMetadata(typeof (ContentItemRecord));
var contentItemVersionMetadata = session.SessionFactory.GetClassMetadata(typeof (ContentItemVersionRecord));
ExpandHints(hintDictionary, contentItemMetadata, contentItemCriteria);
ExpandHints(hintDictionary, contentItemVersionMetadata, contentItemVersionCriteria);
return contentItemVersionCriteria.List<ContentItemVersionRecord>();
}
private static void ExpandHints(Dictionary<string, string> hintDictionary, IClassMetadata recordMetadata, ICriteria recordCriteria) {
foreach (var associationPath in recordMetadata.PropertyNames.Where(hintDictionary.ContainsKey)) {
if (recordCriteria.GetCriteriaByPath(associationPath) == null) {
recordCriteria.CreateCriteria(associationPath, JoinType.LeftOuterJoin);
}
}
}
public virtual void Publish(ContentItem contentItem) {
if (contentItem.VersionRecord.Published) {
return;
@@ -407,8 +483,9 @@ namespace Orchard.ContentManagement {
// Call content item handlers.
public void Import(XElement element, ImportContentSession importContentSession) {
var elementId = element.Attribute("Id");
if (elementId == null)
if (elementId == null) {
return;
}
var identity = elementId.Value;
var status = element.Attribute("Status");
@@ -487,8 +564,8 @@ namespace Orchard.ContentManagement {
}
}
class CallSiteCollection : ConcurrentDictionary<string, CallSite<Func<CallSite, object, object>>> {
readonly Func<string, CallSite<Func<CallSite, object, object>>> _valueFactory;
internal class CallSiteCollection : ConcurrentDictionary<string, CallSite<Func<CallSite, object, object>>> {
private readonly Func<string, CallSite<Func<CallSite, object, object>>> _valueFactory;
public CallSiteCollection(Func<string, CallSite<Func<CallSite, object, object>>> callSiteFactory) {
_valueFactory = callSiteFactory;

View File

@@ -16,6 +16,9 @@ namespace Orchard.ContentManagement {
ContentItem Get(int id, VersionOptions options);
IEnumerable<ContentItem> GetAllVersions(int id);
IEnumerable<T> GetMany<T>(IEnumerable<int> ids, VersionOptions options, QueryHints hints) where T : class, IContent;
IEnumerable<T> GetManyByVersionId<T>(IEnumerable<int> versionRecordIds, QueryHints hints) where T : class, IContent;
void Publish(ContentItem contentItem);
void Unpublish(ContentItem contentItem);
void Remove(ContentItem contentItem);

View File

@@ -0,0 +1,202 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.ContentManagement.Records;
namespace Orchard.ContentManagement
{
public class QueryHints
{
private readonly List<string> _records = new List<string>();
private static readonly QueryHints _empty = new QueryHints();
public IEnumerable<string> Records
{
get { return _records; }
}
public static QueryHints Empty
{
get { return _empty; }
}
public QueryHints ExpandRecords(IEnumerable<string> records)
{
_records.AddRange(records);
return this;
}
public QueryHints ExpandRecords(params string[] records)
{
_records.AddRange(records);
return this;
}
public QueryHints ExpandRecords<TRecord1>() where TRecord1 : ContentPartRecord
{
_records.AddRange(new[] { typeof(TRecord1).Name });
return this;
}
public QueryHints ExpandRecords<TRecord1, TRecord2>()
where TRecord1 : ContentPartRecord
where TRecord2 : ContentPartRecord
{
_records.AddRange(new[] { typeof(TRecord1).Name, typeof(TRecord2).Name });
return this;
}
public QueryHints ExpandRecords<TRecord1, TRecord2, TRecord3>()
where TRecord1 : ContentPartRecord
where TRecord2 : ContentPartRecord
where TRecord3 : ContentPartRecord
{
_records.AddRange(new[] { typeof(TRecord1).Name, typeof(TRecord2).Name, typeof(TRecord3).Name });
return this;
}
public QueryHints ExpandRecords<TRecord1, TRecord2, TRecord3, TRecord4>()
where TRecord1 : ContentPartRecord
where TRecord2 : ContentPartRecord
where TRecord3 : ContentPartRecord
where TRecord4 : ContentPartRecord
{
_records.AddRange(new[] { typeof(TRecord1).Name, typeof(TRecord2).Name, typeof(TRecord3).Name, typeof(TRecord4).Name });
return this;
}
public QueryHints ExpandRecords<TRecord1, TRecord2, TRecord3, TRecord4, TRecord5>()
where TRecord1 : ContentPartRecord
where TRecord2 : ContentPartRecord
where TRecord3 : ContentPartRecord
where TRecord4 : ContentPartRecord
where TRecord5 : ContentPartRecord
{
_records.AddRange(new[] { typeof(TRecord1).Name, typeof(TRecord2).Name, typeof(TRecord3).Name, typeof(TRecord4).Name, typeof(TRecord5).Name });
return this;
}
public QueryHints ExpandRecords<TRecord1, TRecord2, TRecord3, TRecord4, TRecord5, TRecord6>()
where TRecord1 : ContentPartRecord
where TRecord2 : ContentPartRecord
where TRecord3 : ContentPartRecord
where TRecord4 : ContentPartRecord
where TRecord5 : ContentPartRecord
where TRecord6 : ContentPartRecord
{
_records.AddRange(new[] { typeof(TRecord1).Name, typeof(TRecord2).Name, typeof(TRecord3).Name, typeof(TRecord4).Name, typeof(TRecord5).Name, typeof(TRecord6).Name });
return this;
}
public QueryHints ExpandRecords<TRecord1, TRecord2, TRecord3, TRecord4, TRecord5, TRecord6, TRecord7>()
where TRecord1 : ContentPartRecord
where TRecord2 : ContentPartRecord
where TRecord3 : ContentPartRecord
where TRecord4 : ContentPartRecord
where TRecord5 : ContentPartRecord
where TRecord6 : ContentPartRecord
where TRecord7 : ContentPartRecord
{
_records.AddRange(new[] { typeof(TRecord1).Name, typeof(TRecord2).Name, typeof(TRecord3).Name, typeof(TRecord4).Name, typeof(TRecord5).Name, typeof(TRecord6).Name, typeof(TRecord7).Name });
return this;
}
public QueryHints ExpandRecords<TRecord1, TRecord2, TRecord3, TRecord4, TRecord5, TRecord6, TRecord7, TRecord8>()
where TRecord1 : ContentPartRecord
where TRecord2 : ContentPartRecord
where TRecord3 : ContentPartRecord
where TRecord4 : ContentPartRecord
where TRecord5 : ContentPartRecord
where TRecord6 : ContentPartRecord
where TRecord7 : ContentPartRecord
where TRecord8 : ContentPartRecord
{
_records.AddRange(new[] { typeof(TRecord1).Name, typeof(TRecord2).Name, typeof(TRecord3).Name, typeof(TRecord4).Name, typeof(TRecord5).Name, typeof(TRecord6).Name, typeof(TRecord7).Name, typeof(TRecord8).Name });
return this;
}
public QueryHints ExpandParts<TPart1>() where TPart1 : ContentPart
{
return ExpandPartsImpl(typeof(TPart1));
}
public QueryHints ExpandParts<TPart1, TPart2>()
where TPart1 : ContentPart
where TPart2 : ContentPart
{
return ExpandPartsImpl(typeof(TPart1), typeof(TPart2));
}
public QueryHints ExpandParts<TPart1, TPart2, TPart3>()
where TPart1 : ContentPart
where TPart2 : ContentPart
where TPart3 : ContentPart
{
return ExpandPartsImpl(typeof(TPart1), typeof(TPart2), typeof(TPart3));
}
public QueryHints ExpandParts<TPart1, TPart2, TPart3, TPart4>()
where TPart1 : ContentPart
where TPart2 : ContentPart
where TPart3 : ContentPart
where TPart4 : ContentPart
{
return ExpandPartsImpl(typeof(TPart1), typeof(TPart2), typeof(TPart3), typeof(TPart4));
}
public QueryHints ExpandParts<TPart1, TPart2, TPart3, TPart4, TPart5>()
where TPart1 : ContentPart
where TPart2 : ContentPart
where TPart3 : ContentPart
where TPart4 : ContentPart
where TPart5 : ContentPart
{
return ExpandPartsImpl(typeof(TPart1), typeof(TPart2), typeof(TPart3), typeof(TPart4), typeof(TPart5));
}
public QueryHints ExpandParts<TPart1, TPart2, TPart3, TPart4, TPart5, TPart6>()
where TPart1 : ContentPart
where TPart2 : ContentPart
where TPart3 : ContentPart
where TPart4 : ContentPart
where TPart5 : ContentPart
where TPart6 : ContentPart
{
return ExpandPartsImpl(typeof(TPart1), typeof(TPart2), typeof(TPart3), typeof(TPart4), typeof(TPart5), typeof(TPart6));
}
public QueryHints ExpandParts<TPart1, TPart2, TPart3, TPart4, TPart5, TPart6, TPart7>()
where TPart1 : ContentPart
where TPart2 : ContentPart
where TPart3 : ContentPart
where TPart4 : ContentPart
where TPart5 : ContentPart
where TPart6 : ContentPart
where TPart7 : ContentPart
{
return ExpandPartsImpl(typeof(TPart1), typeof(TPart2), typeof(TPart3), typeof(TPart4), typeof(TPart5), typeof(TPart6), typeof(TPart7));
}
public QueryHints ExpandParts<TPart1, TPart2, TPart3, TPart4, TPart5, TPart6, TPart7, TPart8>()
where TPart1 : ContentPart
where TPart2 : ContentPart
where TPart3 : ContentPart
where TPart4 : ContentPart
where TPart5 : ContentPart
where TPart6 : ContentPart
where TPart7 : ContentPart
where TPart8 : ContentPart
{
return ExpandPartsImpl(typeof(TPart1), typeof(TPart2), typeof(TPart3), typeof(TPart4), typeof(TPart5), typeof(TPart6), typeof(TPart7), typeof(TPart8));
}
private QueryHints ExpandPartsImpl(params Type[] parts)
{
foreach (var part in parts)
{
for (var scan = part; scan != typeof(Object); scan = scan.BaseType)
{
if (scan.IsGenericType && scan.GetGenericTypeDefinition() == typeof(ContentPart<>))
{
_records.Add(scan.GetGenericArguments().Single().Name);
break;
}
}
}
return this;
}
}
}

View File

@@ -175,6 +175,7 @@
<Compile Include="ContentManagement\Handlers\ImportContentContext.cs" />
<Compile Include="ContentManagement\IContentBehavior.cs" />
<Compile Include="ContentManagement\ImportContentSession.cs" />
<Compile Include="ContentManagement\QueryHints.cs" />
<Compile Include="ContentManagement\Utilities\ComputedField.cs" />
<Compile Include="DisplayManagement\Descriptors\PlacementInfo.cs" />
<Compile Include="DisplayManagement\Descriptors\ResourceBindingStrategy\StylesheetBindingStrategy.cs" />
@@ -186,6 +187,7 @@
<Compile Include="DisplayManagement\Descriptors\ShapePlacementStrategy\ShapePlacementParsingStrategy.cs" />
<Compile Include="DisplayManagement\Descriptors\ShapeTable.cs" />
<Compile Include="DisplayManagement\Descriptors\ShapeTableBuilder.cs" />
<Compile Include="DisplayManagement\Descriptors\ShapeTableLocator.cs" />
<Compile Include="DisplayManagement\Implementation\IShapeDisplayEvents.cs" />
<Compile Include="DisplayManagement\Implementation\IShapeFactoryEvents.cs" />
<Compile Include="DisplayManagement\Shapes\ShapeDebugView.cs" />
@@ -252,6 +254,7 @@
<Compile Include="Security\Providers\DefaultEncryptionService.cs" />
<Compile Include="Settings\CurrentSiteWorkContext.cs" />
<Compile Include="Settings\ResourceDebugMode.cs" />
<Compile Include="Themes\CurrentThemeWorkContext.cs" />
<Compile Include="Themes\ThemeManager.cs" />
<Compile Include="UI\FlatPositionComparer.cs" />
<Compile Include="UI\Navigation\Pager.cs" />