mirror of
https://github.com/OrchardCMS/Orchard.git
synced 2025-10-15 19:54:57 +08:00
Improving Content Query
Custom extensions IStartingWith, IsEndingWith, IsContaining New IContentQuery.WhereAny to prevent the limitation from QueryOver to handle IEnumerable.Any() in expression queries --HG-- branch : 1.x
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
1f8f582859916d411b5333dd0f32f57da0e72ee8 src/Orchard.Web/Modules/Orchard.AntiSpam
|
||||
bb8c612e72535cbb28b03efb5f7c52e79ced61cd src/Orchard.Web/Modules/Orchard.Autoroute
|
||||
5257b79de7ea0cdcd1bebc04f922fe9bbb127944 src/Orchard.Web/Modules/Orchard.Autoroute
|
||||
2ca2dbbf97b7219f9150d46d52f62bc405c17673 src/Orchard.Web/Modules/Orchard.ContentPermissions
|
||||
e6e70d69f37e48ea6c8784e83a9af4103f5d0dde src/Orchard.Web/Modules/Orchard.ContentPicker
|
||||
b5ccdaed10ff8bcd5bc94d46541209873ae0f722 src/Orchard.Web/Modules/Orchard.CustomForms
|
||||
|
@@ -16,6 +16,7 @@ using Orchard.Tests.ContentManagement.Records;
|
||||
using Orchard.Tests.ContentManagement.Models;
|
||||
using Orchard.DisplayManagement.Implementation;
|
||||
using Orchard.Tests.Stubs;
|
||||
using NHibernate.Impl;
|
||||
|
||||
namespace Orchard.Tests.ContentManagement {
|
||||
[TestFixture]
|
||||
@@ -451,6 +452,59 @@ namespace Orchard.Tests.ContentManagement {
|
||||
Assert.That(listTwo.Count(), Is.EqualTo(2));
|
||||
Assert.That(listThree.Count(), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsStartingExtensionShouldBeUsed() {
|
||||
_manager.Create<GammaPart>("gamma", init => { init.Record.Frap = "one"; });
|
||||
_manager.Create<GammaPart>("gamma", init => { init.Record.Frap = "two"; });
|
||||
_manager.Create<GammaPart>("gamma", init => { init.Record.Frap = "three"; });
|
||||
_manager.Create<GammaPart>("gamma", init => { init.Record.Frap = "four"; });
|
||||
_session.Flush();
|
||||
|
||||
var result = _manager.Query<GammaPart, GammaRecord>()
|
||||
.Where(x => x.Frap.IsStartingWith("t"))
|
||||
.List();
|
||||
|
||||
Assert.That(result.Count(), Is.EqualTo(2));
|
||||
Assert.That(result.Count(x => x.Get<GammaPart>().Record.Frap == "two"), Is.EqualTo(1));
|
||||
Assert.That(result.Count(x => x.Get<GammaPart>().Record.Frap == "three"), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsEndingExtensionShouldBeUsed() {
|
||||
_manager.Create<GammaPart>("gamma", init => { init.Record.Frap = "one"; });
|
||||
_manager.Create<GammaPart>("gamma", init => { init.Record.Frap = "two"; });
|
||||
_manager.Create<GammaPart>("gamma", init => { init.Record.Frap = "three"; });
|
||||
_manager.Create<GammaPart>("gamma", init => { init.Record.Frap = "four"; });
|
||||
_session.Flush();
|
||||
|
||||
var result = _manager.Query<GammaPart, GammaRecord>()
|
||||
.Where(x => x.Frap.IsEndingWith("e"))
|
||||
.List();
|
||||
|
||||
Assert.That(result.Count(), Is.EqualTo(2));
|
||||
Assert.That(result.Count(x => x.Get<GammaPart>().Record.Frap == "one"), Is.EqualTo(1));
|
||||
Assert.That(result.Count(x => x.Get<GammaPart>().Record.Frap == "three"), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void IsContainingExtensionShouldBeUsed() {
|
||||
_manager.Create<GammaPart>("gamma", init => { init.Record.Frap = "one"; });
|
||||
_manager.Create<GammaPart>("gamma", init => { init.Record.Frap = "two"; });
|
||||
_manager.Create<GammaPart>("gamma", init => { init.Record.Frap = "three"; });
|
||||
_manager.Create<GammaPart>("gamma", init => { init.Record.Frap = "four"; });
|
||||
_session.Flush();
|
||||
|
||||
var result = _manager.Query<GammaPart, GammaRecord>()
|
||||
.Where(x => x.Frap.IsContaining("o"))
|
||||
.List();
|
||||
|
||||
Assert.That(result.Count(), Is.EqualTo(3));
|
||||
Assert.That(result.Count(x => x.Get<GammaPart>().Record.Frap == "one"), Is.EqualTo(1));
|
||||
Assert.That(result.Count(x => x.Get<GammaPart>().Record.Frap == "two"), Is.EqualTo(1));
|
||||
Assert.That(result.Count(x => x.Get<GammaPart>().Record.Frap == "four"), Is.EqualTo(1));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -143,8 +143,8 @@ namespace Orchard.Tags.Services {
|
||||
|
||||
public int GetTaggedContentItemCount(int tagId, VersionOptions options) {
|
||||
return _orchardServices.ContentManager
|
||||
.HqlQuery<TagsPart>()
|
||||
.Where(tpr => tpr.ContentPartRecord<TagsPartRecord>().Property("Tags", "tags"), x => x.Eq("TagRecord.Id", tagId))
|
||||
.Query<TagsPart, TagsPartRecord>()
|
||||
.WhereAny(part => part.Tags, tag => tag.Id == tagId)
|
||||
.Count();
|
||||
}
|
||||
|
||||
|
@@ -34,6 +34,9 @@ namespace Orchard.ContentManagement {
|
||||
private const string Published = "Published";
|
||||
private const string Draft = "Draft";
|
||||
|
||||
static DefaultContentManager() {
|
||||
RestrictionExtensions.RegisterExtensions();
|
||||
}
|
||||
public DefaultContentManager(
|
||||
IComponentContext context,
|
||||
IRepository<ContentTypeRecord> contentTypeRepository,
|
||||
|
@@ -103,7 +103,14 @@ namespace Orchard.ContentManagement {
|
||||
}
|
||||
|
||||
private void Where<TRecord>(Expression<Func<TRecord, bool>> predicate) where TRecord : ContentPartRecord {
|
||||
BindPartQueryOver<TRecord>().Where(predicate);
|
||||
var processedCriteria = NHibernate.Impl.ExpressionProcessor.ProcessExpression(predicate);
|
||||
BindPartQueryOver<TRecord>().Where(processedCriteria);
|
||||
//BindPartQueryOver<TRecord>().WithSubquery.WhereSome(.Where(predicate);
|
||||
}
|
||||
|
||||
private void WhereAny<TRecord, TKey>(Expression<Func<TRecord, IEnumerable<TKey>>> selector, Expression<Func<TKey, bool>> predicate) where TRecord : ContentPartRecord {
|
||||
//var address = BindPartQueryOver<TRecord>() QueryOver.Of<TRecord>().Where(selector);
|
||||
BindPartQueryOver<TRecord>().JoinQueryOver<TKey>(selector).Where(predicate);
|
||||
}
|
||||
|
||||
private void OrderBy<TRecord>(Expression<Func<TRecord, object>> keySelector) where TRecord : ContentPartRecord {
|
||||
@@ -256,6 +263,11 @@ namespace Orchard.ContentManagement {
|
||||
return this;
|
||||
}
|
||||
|
||||
IContentQuery<T, TR> IContentQuery<T, TR>.WhereAny<TKey>(Expression<Func<TR, IEnumerable<TKey>>> selector, Expression<Func<TKey, bool>> predicate) {
|
||||
_query.WhereAny(selector, predicate);
|
||||
return this;
|
||||
}
|
||||
|
||||
IContentQuery<T, TR> IContentQuery<T, TR>.OrderBy<TKey>(Expression<Func<TR, TKey>> keySelector) {
|
||||
_query.OrderBy(keySelector);
|
||||
return this;
|
||||
@@ -293,8 +305,6 @@ namespace Orchard.ContentManagement {
|
||||
.GroupBy(item => item.Segments.FirstOrDefault())
|
||||
.ToDictionary(grouping => grouping.Key, StringComparer.InvariantCultureIgnoreCase);
|
||||
|
||||
var aggregatedProperty = false;
|
||||
|
||||
// locate hints that match properties in the ContentItemVersionRecord
|
||||
foreach (var hit in contentItemVersionMetadata.PropertyNames.Where(hintDictionary.ContainsKey).SelectMany(key => hintDictionary[key])) {
|
||||
contentItemVersionCriteria.UnderlyingCriteria.SetFetchMode(hit.Hint, FetchMode.Eager);
|
||||
|
@@ -1,77 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ClassDiagram MajorVersion="1" MinorVersion="1" MembersFormat="FullSignature">
|
||||
<Class Name="Orchard.Models.ContentItem">
|
||||
<Position X="0.5" Y="1.25" Width="2.5" />
|
||||
<Members>
|
||||
<Property Name="IContent.ContentItem" Hidden="true" />
|
||||
</Members>
|
||||
<TypeIdentifier>
|
||||
<HashCode>AAACAAAAAAACAAhAABAAAAAAAAAAQABAAAAQAAAEBAA=</HashCode>
|
||||
<FileName>Models\ContentItem.cs</FileName>
|
||||
</TypeIdentifier>
|
||||
<ShowAsAssociation>
|
||||
<Property Name="Record" />
|
||||
</ShowAsAssociation>
|
||||
<ShowAsCollectionAssociation>
|
||||
<Property Name="Parts" />
|
||||
</ShowAsCollectionAssociation>
|
||||
<Lollipop Position="0.2" />
|
||||
</Class>
|
||||
<Class Name="Orchard.Models.ContentPart">
|
||||
<Position X="5.75" Y="2.25" Width="1.5" />
|
||||
<TypeIdentifier>
|
||||
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAA=</HashCode>
|
||||
<FileName>Models\ContentPart.cs</FileName>
|
||||
</TypeIdentifier>
|
||||
<ShowAsAssociation>
|
||||
<Property Name="ContentItem" />
|
||||
</ShowAsAssociation>
|
||||
<Lollipop Position="0.2" />
|
||||
</Class>
|
||||
<Class Name="Orchard.Models.ContentPart<TRecord>">
|
||||
<Position X="5.25" Y="4" Width="2.5" />
|
||||
<TypeIdentifier>
|
||||
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAA=</HashCode>
|
||||
<FileName>Models\ContentPart.cs</FileName>
|
||||
</TypeIdentifier>
|
||||
</Class>
|
||||
<Class Name="Orchard.Models.Records.ContentItemRecord">
|
||||
<Position X="0.5" Y="4.75" Width="2.5" />
|
||||
<TypeIdentifier>
|
||||
<HashCode>AAACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAA=</HashCode>
|
||||
<FileName>Models\Records\ContentItemRecord.cs</FileName>
|
||||
</TypeIdentifier>
|
||||
<ShowAsAssociation>
|
||||
<Property Name="ContentType" />
|
||||
</ShowAsAssociation>
|
||||
</Class>
|
||||
<Class Name="Orchard.Models.Records.ContentTypeRecord">
|
||||
<Position X="0.5" Y="6.5" Width="2.25" />
|
||||
<TypeIdentifier>
|
||||
<HashCode>AAACAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAA=</HashCode>
|
||||
<FileName>Models\Records\ContentTypeRecord.cs</FileName>
|
||||
</TypeIdentifier>
|
||||
</Class>
|
||||
<Interface Name="Orchard.Models.IContent">
|
||||
<Position X="5.5" Y="0.5" Width="2.25" />
|
||||
<TypeIdentifier>
|
||||
<HashCode>AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAA=</HashCode>
|
||||
<FileName>Models\IContent.cs</FileName>
|
||||
</TypeIdentifier>
|
||||
</Interface>
|
||||
<Interface Name="Orchard.Models.IContentManager">
|
||||
<Position X="4" Y="5.75" Width="6" />
|
||||
<TypeIdentifier>
|
||||
<HashCode>AAAAEAAAAAAAACBBAIAAAAAAAAEAAEgAAACAAAAAAAA=</HashCode>
|
||||
<FileName>Models\IContentManager.cs</FileName>
|
||||
</TypeIdentifier>
|
||||
</Interface>
|
||||
<Interface Name="Orchard.Models.Driver.IContentHandler">
|
||||
<Position X="4.5" Y="8.75" Width="4.75" />
|
||||
<TypeIdentifier>
|
||||
<HashCode>AAAAEAAAAAEAAABBAIAAAIAAACEAAAQAAACAAAAAAAg=</HashCode>
|
||||
<FileName>Models\Driver\IContentHandler.cs</FileName>
|
||||
</TypeIdentifier>
|
||||
</Interface>
|
||||
<Font Name="Segoe UI" Size="9" />
|
||||
</ClassDiagram>
|
@@ -32,6 +32,7 @@ namespace Orchard.ContentManagement {
|
||||
new IContentQuery<TPart, TRecord> ForVersion(VersionOptions options);
|
||||
|
||||
IContentQuery<TPart, TRecord> Where(Expression<Func<TRecord, bool>> predicate);
|
||||
IContentQuery<TPart, TRecord> WhereAny<TKey>(Expression<Func<TRecord, IEnumerable<TKey>>> selector, Expression<Func<TKey, bool>> predicate);
|
||||
IContentQuery<TPart, TRecord> OrderBy(Expression<Func<TRecord, object>> keySelector);
|
||||
IContentQuery<TPart, TRecord> OrderByDescending(Expression<Func<TRecord, object>> keySelector);
|
||||
|
||||
|
53
src/Orchard/ContentManagement/RestrictionExtensions.cs
Normal file
53
src/Orchard/ContentManagement/RestrictionExtensions.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
using NHibernate.Criterion;
|
||||
using NHibernate.Impl;
|
||||
using Orchard.ContentManagement.Records;
|
||||
|
||||
namespace Orchard.ContentManagement {
|
||||
public static class RestrictionExtensions {
|
||||
public static void RegisterExtensions() {
|
||||
ExpressionProcessor.RegisterCustomMethodCall(() => RestrictionExtensions.IsStartingWith("", ""), RestrictionExtensions.ProcessIsStartingWith);
|
||||
ExpressionProcessor.RegisterCustomMethodCall(() => RestrictionExtensions.IsEndingWith("", ""), RestrictionExtensions.ProcessIsEndingWith);
|
||||
ExpressionProcessor.RegisterCustomMethodCall(() => RestrictionExtensions.IsContaining("", ""), RestrictionExtensions.ProcessIsContaining);
|
||||
}
|
||||
|
||||
public static bool IsStartingWith(this string item, string value) {
|
||||
throw new NotImplementedException("Do not use this method directly");
|
||||
}
|
||||
|
||||
public static bool IsEndingWith(this string item, string value) {
|
||||
throw new NotImplementedException("Do not use this method directly");
|
||||
}
|
||||
|
||||
public static bool IsContaining(this string item, string value) {
|
||||
throw new NotImplementedException("Do not use this method directly");
|
||||
}
|
||||
|
||||
public static ICriterion ProcessIsStartingWith(MethodCallExpression methodCallExpression) {
|
||||
ExpressionProcessor.ProjectionInfo projection = ExpressionProcessor.FindMemberProjection(methodCallExpression.Arguments[0]);
|
||||
string value = (string)ExpressionProcessor.FindValue(methodCallExpression.Arguments[1]);
|
||||
MatchMode matchMode = MatchMode.Start;
|
||||
return projection.Create<ICriterion>(s => Restrictions.InsensitiveLike(s, value, matchMode), p => Restrictions.InsensitiveLike(p, value, matchMode));
|
||||
}
|
||||
|
||||
|
||||
public static ICriterion ProcessIsEndingWith(MethodCallExpression methodCallExpression) {
|
||||
ExpressionProcessor.ProjectionInfo projection = ExpressionProcessor.FindMemberProjection(methodCallExpression.Arguments[0]);
|
||||
string value = (string)ExpressionProcessor.FindValue(methodCallExpression.Arguments[1]);
|
||||
MatchMode matchMode = MatchMode.End;
|
||||
return projection.Create<ICriterion>(s => Restrictions.InsensitiveLike(s, value, matchMode), p => Restrictions.InsensitiveLike(p, value, matchMode));
|
||||
}
|
||||
|
||||
|
||||
public static ICriterion ProcessIsContaining(MethodCallExpression methodCallExpression) {
|
||||
ExpressionProcessor.ProjectionInfo projection = ExpressionProcessor.FindMemberProjection(methodCallExpression.Arguments[0]);
|
||||
string value = (string)ExpressionProcessor.FindValue(methodCallExpression.Arguments[1]);
|
||||
MatchMode matchMode = MatchMode.Anywhere;
|
||||
return projection.Create<ICriterion>(s => Restrictions.InsensitiveLike(s, value, matchMode), p => Restrictions.InsensitiveLike(p, value, matchMode));
|
||||
}
|
||||
}
|
||||
}
|
@@ -171,6 +171,7 @@
|
||||
<Compile Include="ContentManagement\ImportContentSession.cs" />
|
||||
<Compile Include="ContentManagement\MetaData\Services\ISettingsFormatter.cs" />
|
||||
<Compile Include="ContentManagement\QueryHints.cs" />
|
||||
<Compile Include="ContentManagement\RestrictionExtensions.cs" />
|
||||
<Compile Include="ContentManagement\Utilities\ComputedField.cs" />
|
||||
<Compile Include="Data\Conventions\AggregateAttribute.cs" />
|
||||
<Compile Include="Data\Conventions\CacheConvention.cs" />
|
||||
@@ -906,7 +907,6 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="app.config" />
|
||||
<None Include="ContentManagement\Diagram.cd" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<BootstrapperPackage Include="Microsoft.Net.Client.3.5">
|
||||
|
Reference in New Issue
Block a user