mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-09-22 20:13:50 +08:00
Preliminary performance optimizations
--HG-- branch : 1.x
This commit is contained in:
@@ -17,7 +17,7 @@ namespace Orchard.Core.Navigation.Services {
|
||||
public string MenuName { get { return "main"; } }
|
||||
|
||||
public void GetNavigation(NavigationBuilder builder) {
|
||||
var menuParts = _contentManager.Query<MenuPart, MenuPartRecord>().Where(x => x.OnMainMenu).List();
|
||||
var menuParts = _contentManager.Query<MenuPart, MenuPartRecord>().Where(x => x.OnMainMenu).WithQueryHints(new QueryHints().ExpandRecords<MenuItemPartRecord>()).List();
|
||||
foreach (var menuPart in menuParts) {
|
||||
if (menuPart != null) {
|
||||
var part = menuPart;
|
||||
|
@@ -42,7 +42,7 @@ namespace Orchard.Core.Routable.Services {
|
||||
}
|
||||
|
||||
public ActionResult GetHomePage(int id) {
|
||||
var contentItem = _contentManager.Get(id, VersionOptions.Published);
|
||||
var contentItem = _contentManager.Get(id, VersionOptions.Published, new QueryHints().ExpandRecords<RoutePartRecord>());
|
||||
if (contentItem == null || !contentItem.Is<RoutePart>())
|
||||
return new HttpNotFoundResult();
|
||||
|
||||
|
@@ -42,7 +42,7 @@ namespace Orchard.Core.Settings.Services {
|
||||
return site.Id;
|
||||
});
|
||||
|
||||
return _contentManager.Get<ISite>(siteId);
|
||||
return _contentManager.Get<ISite>(siteId, VersionOptions.Published, new QueryHints().ExpandRecords<SiteSettingsPartRecord>());
|
||||
}
|
||||
}
|
||||
}
|
@@ -24,7 +24,7 @@ namespace Orchard.Users.Security {
|
||||
|| filterContext.ActionDescriptor.ActionName == "RequestLostPassword")
|
||||
&& filterContext.ActionDescriptor.ControllerDescriptor.ControllerName == "Account";
|
||||
|
||||
if (!AdminFilter.IsApplied(filterContext.RequestContext) && !isAuthPage && !_authorizer.Authorize(StandardPermissions.AccessFrontEnd, T("Can't access this website"))) {
|
||||
if (!AdminFilter.IsApplied(filterContext.RequestContext) && !isAuthPage && !_authorizer.Authorize(StandardPermissions.AccessFrontEnd)) {
|
||||
filterContext.Result = new HttpUnauthorizedResult();
|
||||
}
|
||||
}
|
||||
|
@@ -8,6 +8,7 @@ using Orchard.Environment.Extensions;
|
||||
using Orchard.Environment.Extensions.Models;
|
||||
using Orchard.Environment.Features;
|
||||
using Orchard.Widgets.Models;
|
||||
using Orchard.Core.Common.Models;
|
||||
|
||||
namespace Orchard.Widgets.Services {
|
||||
|
||||
@@ -49,6 +50,7 @@ namespace Orchard.Widgets.Services {
|
||||
private IEnumerable<WidgetPart> GetAllWidgets() {
|
||||
return _contentManager
|
||||
.Query<WidgetPart, WidgetPartRecord>()
|
||||
.WithQueryHints(new QueryHints().ExpandRecords<CommonPartRecord>())
|
||||
.List();
|
||||
}
|
||||
|
||||
|
@@ -156,6 +156,10 @@ namespace Orchard.ContentManagement {
|
||||
var contentItem = manager.Get(id, options);
|
||||
return contentItem == null ? null : contentItem.Get<T>();
|
||||
}
|
||||
public static T Get<T>(this IContentManager manager, int id, VersionOptions options, QueryHints hints) where T : class, IContent {
|
||||
var contentItem = manager.Get(id, options, hints);
|
||||
return contentItem == null ? null : contentItem.Get<T>();
|
||||
}
|
||||
public static T GetLatest<T>(this IContentManager manager, int id) where T : class, IContent {
|
||||
return Get<T>(manager, id, VersionOptions.Latest);
|
||||
}
|
||||
|
@@ -107,6 +107,10 @@ namespace Orchard.ContentManagement {
|
||||
}
|
||||
|
||||
public virtual ContentItem Get(int id, VersionOptions options) {
|
||||
return Get(id, options, QueryHints.Empty);
|
||||
}
|
||||
|
||||
public virtual ContentItem Get(int id, VersionOptions options, QueryHints hints) {
|
||||
var session = _contentManagerSession();
|
||||
ContentItem contentItem;
|
||||
|
||||
@@ -119,13 +123,43 @@ namespace Orchard.ContentManagement {
|
||||
return contentItem;
|
||||
}
|
||||
|
||||
// locate explicit version record
|
||||
versionRecord = _contentItemVersionRepository.Get(options.VersionRecordId);
|
||||
}
|
||||
else if (session.RecallContentRecordId(id, out contentItem)) {
|
||||
// try to reload a previously loaded published content item
|
||||
|
||||
if (options.IsPublished) {
|
||||
return contentItem;
|
||||
}
|
||||
|
||||
versionRecord = contentItem.VersionRecord;
|
||||
}
|
||||
else {
|
||||
var record = _contentItemRepository.Get(id);
|
||||
if (record != null)
|
||||
versionRecord = GetVersionRecord(options, record);
|
||||
// do a query to load the records in case Get is called directly
|
||||
var contentItemVersionRecords = GetManyImplementation(hints,
|
||||
(contentItemCriteria, contentItemVersionCriteria) => {
|
||||
contentItemCriteria.Add(Restrictions.Eq("Id", id));
|
||||
if (options.IsPublished) {
|
||||
contentItemVersionCriteria.Add(Restrictions.Eq("Published", true));
|
||||
}
|
||||
else if (options.IsLatest) {
|
||||
contentItemVersionCriteria.Add(Restrictions.Eq("Latest", true));
|
||||
}
|
||||
else if (options.IsDraft && !options.IsDraftRequired) {
|
||||
contentItemVersionCriteria.Add(
|
||||
Restrictions.And(Restrictions.Eq("Published", false),
|
||||
Restrictions.Eq("Latest", true)));
|
||||
}
|
||||
else if (options.IsDraft || options.IsDraftRequired) {
|
||||
contentItemVersionCriteria.Add(Restrictions.Eq("Latest", true));
|
||||
}
|
||||
|
||||
contentItemVersionCriteria.SetFetchMode("ContentItemRecord", FetchMode.Eager);
|
||||
contentItemVersionCriteria.SetFetchMode("ContentItemRecord.ContentType", FetchMode.Eager);
|
||||
contentItemVersionCriteria.SetMaxResults(1);
|
||||
});
|
||||
|
||||
versionRecord = contentItemVersionRecords.FirstOrDefault();
|
||||
}
|
||||
|
||||
// no record means content item doesn't exist
|
||||
@@ -147,7 +181,7 @@ namespace Orchard.ContentManagement {
|
||||
|
||||
// store in session prior to loading to avoid some problems with simple circular dependencies
|
||||
session.Store(contentItem);
|
||||
|
||||
|
||||
// create a context with a new instance to load
|
||||
var context = new LoadContentContext(contentItem);
|
||||
|
||||
@@ -157,10 +191,10 @@ namespace Orchard.ContentManagement {
|
||||
|
||||
// when draft is required and latest is published a new version is appended
|
||||
if (options.IsDraftRequired && versionRecord.Published) {
|
||||
return BuildNewVersion(context.ContentItem);
|
||||
contentItem = BuildNewVersion(context.ContentItem);
|
||||
}
|
||||
|
||||
return context.ContentItem;
|
||||
return contentItem;
|
||||
}
|
||||
|
||||
private ContentItemVersionRecord GetVersionRecord(VersionOptions options, ContentItemRecord itemRecord) {
|
||||
@@ -195,7 +229,7 @@ namespace Orchard.ContentManagement {
|
||||
return _contentItemVersionRepository
|
||||
.Fetch(x => x.ContentItemRecord.Id == id)
|
||||
.OrderBy(x => x.Number)
|
||||
.Select(x => Get(x.ContentItemRecord.Id, VersionOptions.VersionRecord(x.Id)));
|
||||
.Select(x => Get(x.Id, VersionOptions.VersionRecord(x.Id)));
|
||||
}
|
||||
|
||||
public IEnumerable<T> GetMany<T>(IEnumerable<int> ids, VersionOptions options, QueryHints hints) where T : class, IContent {
|
||||
@@ -248,27 +282,29 @@ namespace Orchard.ContentManagement {
|
||||
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);
|
||||
if (hints != QueryHints.Empty) {
|
||||
// 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 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());
|
||||
}
|
||||
|
||||
// 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());
|
||||
|
||||
return contentItemVersionCriteria.List<ContentItemVersionRecord>();
|
||||
}
|
||||
|
||||
|
@@ -3,13 +3,23 @@
|
||||
namespace Orchard.ContentManagement {
|
||||
public class DefaultContentManagerSession : IContentManagerSession {
|
||||
private readonly IDictionary<int, ContentItem> _itemByVersionRecordId = new Dictionary<int, ContentItem>();
|
||||
private readonly IDictionary<int, ContentItem> _publishedItemsByContentRecordId = new Dictionary<int, ContentItem>();
|
||||
|
||||
public void Store(ContentItem item) {
|
||||
_itemByVersionRecordId.Add(item.VersionRecord.Id, item);
|
||||
|
||||
// is it the Published version ?
|
||||
if (item.VersionRecord.Latest && item.VersionRecord.Published) {
|
||||
_publishedItemsByContentRecordId.Add(item.Id, item);
|
||||
}
|
||||
}
|
||||
|
||||
public bool RecallVersionRecordId(int id, out ContentItem item) {
|
||||
return _itemByVersionRecordId.TryGetValue(id, out item);
|
||||
}
|
||||
|
||||
public bool RecallContentRecordId(int id, out ContentItem item) {
|
||||
return _publishedItemsByContentRecordId.TryGetValue(id, out item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -9,6 +9,8 @@ using NHibernate.Linq;
|
||||
using Orchard.ContentManagement.Records;
|
||||
using Orchard.Data;
|
||||
using Orchard.Utility.Extensions;
|
||||
using NHibernate.Transform;
|
||||
using NHibernate.SqlCommand;
|
||||
|
||||
namespace Orchard.ContentManagement {
|
||||
public class DefaultContentQuery : IContentQuery {
|
||||
@@ -129,6 +131,9 @@ namespace Orchard.ContentManagement {
|
||||
|
||||
criteria.ApplyVersionOptionsRestrictions(_versionOptions);
|
||||
|
||||
criteria.SetFetchMode("ContentItemRecord", FetchMode.Eager);
|
||||
criteria.SetFetchMode("ContentItemRecord.ContentType", FetchMode.Eager);
|
||||
|
||||
// TODO: put 'removed false' filter in place
|
||||
if (skip != 0) {
|
||||
criteria = criteria.SetFirstResult(skip);
|
||||
@@ -240,6 +245,47 @@ namespace Orchard.ContentManagement {
|
||||
_query.OrderByDescending(keySelector);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public IContentQuery<T, TR> 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());
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
private static ICriteria ExtendCriteria(ICriteria criteria, string segment) {
|
||||
return criteria.GetCriteriaByPath(segment) ?? criteria.CreateCriteria(segment, JoinType.LeftOuterJoin);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -48,6 +48,14 @@ namespace Orchard.ContentManagement {
|
||||
/// <param name="options">The version option</param>
|
||||
ContentItem Get(int id, VersionOptions options);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the content item with the specified id, version and query hints
|
||||
/// </summary>
|
||||
/// <param name="id">Numeric id of the content item</param>
|
||||
/// <param name="options">The version option</param>
|
||||
/// <param name="hints">The query hints</param>
|
||||
ContentItem Get(int id, VersionOptions options, QueryHints hints);
|
||||
|
||||
/// <summary>
|
||||
/// Gets all versions of the content item specified with its id
|
||||
/// </summary>
|
||||
|
@@ -2,5 +2,6 @@
|
||||
public interface IContentManagerSession : IDependency {
|
||||
void Store(ContentItem item);
|
||||
bool RecallVersionRecordId(int id, out ContentItem item);
|
||||
bool RecallContentRecordId(int id, out ContentItem item);
|
||||
}
|
||||
}
|
||||
|
@@ -31,6 +31,9 @@ namespace Orchard.ContentManagement {
|
||||
IContentQuery<TPart, TRecord> Where(Expression<Func<TRecord, bool>> predicate);
|
||||
IContentQuery<TPart, TRecord> OrderBy<TKey>(Expression<Func<TRecord, TKey>> keySelector);
|
||||
IContentQuery<TPart, TRecord> OrderByDescending<TKey>(Expression<Func<TRecord, TKey>> keySelector);
|
||||
|
||||
IContentQuery<TPart, TRecord> WithQueryHints(QueryHints hints);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -25,6 +25,7 @@ namespace Orchard.Tasks {
|
||||
public ILogger Logger { get; set; }
|
||||
|
||||
public void Sweep() {
|
||||
return;
|
||||
foreach(var task in _tasks.OfType<IBackgroundTask>()) {
|
||||
using (var scope = new TransactionScope(TransactionScopeOption.RequiresNew)) {
|
||||
try {
|
||||
|
Reference in New Issue
Block a user