Implementing eager fetching for Hql queries

This commit is contained in:
Sebastien Ros 2013-10-03 11:22:02 -07:00
parent 840975e6b4
commit 1235f226d3
5 changed files with 123 additions and 10 deletions

View File

@ -130,6 +130,8 @@
<Compile Include="Models\NavigationQueryPart.cs" />
<Compile Include="Models\NavigationQueryPartRecord.cs" />
<Compile Include="Models\QueryPart.cs" />
<Compile Include="Providers\Filters\ContentPartsForm.cs" />
<Compile Include="Providers\Filters\EagerFetchFilter.cs" />
<Compile Include="Providers\Layouts\RawLayout.cs" />
<Compile Include="Providers\Layouts\RawLayoutForms.cs" />
<Compile Include="Providers\Layouts\RawShapes.cs" />

View File

@ -0,0 +1,51 @@
using System;
using System.Linq;
using System.Web.Mvc;
using Orchard.ContentManagement.MetaData;
using Orchard.DisplayManagement;
using Orchard.Forms.Services;
using Orchard.Localization;
namespace Orchard.Projections.Providers.Filters {
public class ContentPartsForm : IFormProvider {
private readonly IContentDefinitionManager _contentDefinitionManager;
protected dynamic Shape { get; set; }
public Localizer T { get; set; }
public ContentPartsForm(
IShapeFactory shapeFactory,
IContentDefinitionManager contentDefinitionManager) {
_contentDefinitionManager = contentDefinitionManager;
Shape = shapeFactory;
T = NullLocalizer.Instance;
}
public void Describe(DescribeContext context) {
Func<IShapeFactory, object> form =
shape => {
var f = Shape.Form(
Id: "AnyOfContentParts",
_Parts: Shape.SelectList(
Id: "contentparts", Name: "ContentParts",
Title: T("Content parts"),
Description: T("Select some content parts."),
Size: 10,
Multiple: true
)
);
f._Parts.Add(new SelectListItem { Value = "", Text = T("Any").Text });
foreach (var contentPart in _contentDefinitionManager.ListPartDefinitions().OrderBy(x => x.Name)) {
f._Parts.Add(new SelectListItem { Value = contentPart.Name, Text = contentPart.Name });
}
return f;
};
context.Form("ContentPartsForm", form);
}
}
}

View File

@ -0,0 +1,42 @@
using System;
using Orchard.Localization;
using Orchard.Projections.Descriptors.Filter;
using IFilterProvider = Orchard.Projections.Services.IFilterProvider;
namespace Orchard.Projections.Providers.Filters {
public class EagerFectchFilter : IFilterProvider {
public EagerFectchFilter() {
T = NullLocalizer.Instance;
}
public Localizer T { get; set; }
public void Describe(DescribeFilterContext describe) {
describe.For("Content", T("Content"),T("Content"))
.Element("EagerFetch", T("Eager fetch"), T("Eager fetch content parts"),
ApplyFilter,
DisplayFilter,
"ContentPartsForm"
);
}
public void ApplyFilter(FilterContext context) {
var contentPartNames = (string)context.State.ContentParts;
if (!String.IsNullOrEmpty(contentPartNames)) {
var contentParts = contentPartNames.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
context.Query = context.Query.Include(contentParts);
}
}
public LocalizedString DisplayFilter(FilterContext context) {
string contentparts = context.State.ContentParts;
if (String.IsNullOrEmpty(contentparts)) {
return T("No content part");
}
return T("Eager fetch parts {0}", contentparts);
}
}
}

View File

@ -18,14 +18,14 @@ namespace Orchard.ContentManagement {
private readonly IEnumerable<ISqlStatementProvider> _sqlStatementProviders;
private readonly ShellSettings _shellSettings;
private VersionOptions _versionOptions;
private string[] _includedPartNames = new string[0];
private bool _cacheable;
protected IJoin _from;
protected readonly List<Tuple<IAlias, Join>> _joins = new List<Tuple<IAlias, Join>>();
protected readonly List<Tuple<IAlias, Action<IHqlExpressionFactory>>> _wheres = new List<Tuple<IAlias, Action<IHqlExpressionFactory>>>();
protected readonly List<Tuple<IAlias, Action<IHqlSortFactory>>> _sortings = new List<Tuple<IAlias, Action<IHqlSortFactory>>>();
private bool cacheable;
public IContentManager ContentManager { get; private set; }
public DefaultHqlQuery(
@ -74,13 +74,18 @@ namespace Orchard.ContentManagement {
return BindCriteriaByAlias(BindItemCriteria(), "ContentType", "ct");
}
internal IAlias BindItemCriteria() {
internal IAlias BindItemCriteria(string type = "") {
// [ContentItemVersionRecord] >join> [ContentItemRecord]
return BindCriteriaByAlias(BindItemVersionCriteria(), typeof(ContentItemRecord).Name, "ci");
return BindCriteriaByAlias(BindItemVersionCriteria(type), typeof(ContentItemRecord).Name, "ci");
}
internal IAlias BindItemVersionCriteria() {
return _from ?? (_from = new Join(typeof(ContentItemVersionRecord).FullName, "civ", ""));
internal IAlias BindItemVersionCriteria(string type = "") {
_from = _from ?? new Join(typeof(ContentItemVersionRecord).FullName, "civ", type);
if (_from.Type.Length < type.Length) {
_from.Type = type;
}
return _from;
}
internal IAlias BindPartCriteria<TRecord>() where TRecord : ContentPartRecord {
@ -152,6 +157,12 @@ namespace Orchard.ContentManagement {
if (contentTypeNames != null && contentTypeNames.Length != 0) {
Where(BindTypeCriteria(), x => x.InG("Name", contentTypeNames));
}
return this;
}
public IHqlQuery Include(params string[] partNames) {
_includedPartNames = _includedPartNames.Union(partNames).ToArray();
return this;
}
@ -170,13 +181,13 @@ namespace Orchard.ContentManagement {
public IEnumerable<ContentItem> Slice(int skip, int count) {
ApplyHqlVersionOptionsRestrictions(_versionOptions);
cacheable = true;
_cacheable = true;
var hql = ToHql(false);
var query = _session
.CreateQuery(hql)
.SetCacheable(cacheable)
.SetCacheable(_cacheable)
;
if (skip != 0) {
@ -191,7 +202,9 @@ namespace Orchard.ContentManagement {
.List<IDictionary>()
.Select(x => (int)x["Id"]);
return ContentManager.GetManyByVersionId(ids, QueryHints.Empty);
var contentPartRecords = _includedPartNames.Select(part => part + "Record").ToList();
return ContentManager.GetManyByVersionId(ids, new QueryHints().ExpandRecords(contentPartRecords));
}
public int Count() {
@ -224,7 +237,7 @@ namespace Orchard.ContentManagement {
}
else {
// select distinct can't be used with newid()
cacheable = false;
_cacheable = false;
sb.Replace("select distinct", "select ");
}
}

View File

@ -18,6 +18,11 @@ namespace Orchard.ContentManagement {
/// Add content type constraints to the query.
/// </summary>
IHqlQuery ForType(params string[] contentTypes);
/// <summary>
/// Eagerly fetches specific content parts.
/// </summary>
IHqlQuery Include(params string[] contentParts);
/// <summary>
/// Adds versioning options to the query.