Adding strongly typed IContentQuery interfaces

--HG--
extra : convert_revision : svn%3A5ff7c347-ad56-4c35-b696-ccb81de16e03/trunk%4042412
This commit is contained in:
loudej
2009-11-27 04:55:05 +00:00
parent 0c0b49dfc9
commit 3c0f413e34
18 changed files with 195 additions and 85 deletions

View File

@@ -156,8 +156,8 @@ namespace Orchard.Tests.Models {
_manager.Create<Gamma>("gamma", init => { init.Record.Frap = "four"; });
_session.Flush();
var twoOrFour = _manager.Query()
.Where<GammaRecord>(x => x.Frap == "one" || x.Frap == "four")
var twoOrFour = _manager.Query<Gamma, GammaRecord>()
.Where(x => x.Frap == "one" || x.Frap == "four")
.List();
Assert.That(twoOrFour.Count(), Is.EqualTo(2));
@@ -170,8 +170,8 @@ namespace Orchard.Tests.Models {
[Test]
public void EmptyWherePredicateRequiresRecord() {
AddSampleData();
var gammas = _manager.Query().Where<GammaRecord>().List();
var deltas = _manager.Query().Where<DeltaRecord>().List();
var gammas = _manager.Query().Join<GammaRecord>().List();
var deltas = _manager.Query().Join<DeltaRecord>().List();
Assert.That(gammas.Count(), Is.EqualTo(1));
Assert.That(deltas.Count(), Is.EqualTo(1));
@@ -197,9 +197,9 @@ namespace Orchard.Tests.Models {
Assert.That(ascending.Last().Record.Frap, Is.EqualTo("two"));
var descending = _manager.Query("gamma")
.OrderByDescending<GammaRecord, string>(x => x.Frap)
.List<Gamma>();
var descending = _manager.Query<Gamma, GammaRecord>()
.OrderByDescending(x => x.Frap)
.List();
Assert.That(descending.Count(), Is.EqualTo(5));
Assert.That(descending.First().Record.Frap, Is.EqualTo("two"));
@@ -216,11 +216,11 @@ namespace Orchard.Tests.Models {
_session.Flush();
var reverseById = _manager.Query()
.OrderByDescending<ContentItemRecord, int>(x => x.Id)
.OrderByDescending<GammaRecord, int>(x => x.Id)
.List();
var subset = _manager.Query()
.OrderByDescending<ContentItemRecord, int>(x => x.Id)
.OrderByDescending<GammaRecord, int>(x => x.Id)
.Slice(2, 3);
Assert.That(subset.Count(), Is.EqualTo(3));

View File

@@ -120,7 +120,7 @@ namespace Orchard.Tests.Models {
// create a gamma record
var gamma = new GammaRecord {
ContentItem = _container.Resolve<IRepository<ContentItemRecord>>().Get(model.Id),
ContentItemRecord = _container.Resolve<IRepository<ContentItemRecord>>().Get(model.Id),
Frap = "foo"
};
@@ -135,7 +135,7 @@ namespace Orchard.Tests.Models {
Assert.That(model.Id, Is.EqualTo(modelRecord.Id));
Assert.That(model.Is<Gamma>(), Is.True);
Assert.That(model.As<Gamma>().Record, Is.Not.Null);
Assert.That(model.As<Gamma>().Record.ContentItem.Id, Is.EqualTo(model.Id));
Assert.That(model.As<Gamma>().Record.ContentItemRecord.Id, Is.EqualTo(model.Id));
}

View File

@@ -18,7 +18,7 @@ namespace Orchard.Blogs.Services {
public BlogPost Get(Blog blog, string slug) {
RoutableRecord record =
_routableRepository.Get(r => r.ContentItem.ContentType.Name == "blogpost" && r.Slug == slug);
_routableRepository.Get(r => r.ContentItemRecord.ContentType.Name == "blogpost" && r.Slug == slug);
BlogPost blogPost = record != null ? _contentManager.Get<BlogPost>(record.Id) : null;
return blogPost != null && blogPost.Record.Blog.Id == blog.ContentItem.Id ? blogPost : null;
@@ -27,7 +27,7 @@ namespace Orchard.Blogs.Services {
public IEnumerable<BlogPost> Get(Blog blog) {
//TODO: (erikpo) Figure out how to sort by published date
IEnumerable<RoutableRecord> records =
_routableRepository.Fetch(rr => rr.ContentItem.ContentType.Name == "blogpost"
_routableRepository.Fetch(rr => rr.ContentItemRecord.ContentType.Name == "blogpost"
/*, bpr => bpr.Asc(bpr2 => bpr2.Published.GetValueOrDefault(new DateTime(2099, 1, 1)))*/);
//TODO: (erikpo) Need to filter by blog in the line above instead of filtering here

View File

@@ -17,13 +17,13 @@ namespace Orchard.Blogs.Services {
}
public Blog Get(string slug) {
RoutableRecord record = _routableRepository.Get(r => r.ContentItem.ContentType.Name == "blog" && r.Slug == slug);
RoutableRecord record = _routableRepository.Get(r => r.ContentItemRecord.ContentType.Name == "blog" && r.Slug == slug);
return record != null ?_contentManager.Get<Blog>(record.Id) : null;
}
public IEnumerable<Blog> Get() {
IEnumerable<RoutableRecord> records = _routableRepository.Fetch(rr => rr.ContentItem.ContentType.Name == "blog", rr => rr.Asc(rr2 => rr2.Title));
IEnumerable<RoutableRecord> records = _routableRepository.Fetch(rr => rr.ContentItemRecord.ContentType.Name == "blog", rr => rr.Asc(rr2 => rr2.Title));
return records.Select(rr => _contentManager.Get<Blog>(rr.Id));
}

View File

@@ -26,7 +26,7 @@ namespace Orchard.DevTools.Controllers {
public ActionResult Index() {
return View(new ContentIndexViewModel {
Items = _contentManager.Query().OrderBy<ContentItemRecord, int>(x => x.Id).List(),
Items = _contentManager.Query().List(),
Types = _contentTypeRepository.Table.ToList()
});
}

View File

@@ -29,18 +29,19 @@ namespace Orchard.Sandbox.Controllers {
public ActionResult Index() {
var model = new PageIndexViewModel {
Pages = _contentManager.Query()
.OrderBy<SandboxPageRecord, string>(x => x.Name)
.List<SandboxPage>()
Pages = _contentManager.Query<SandboxPage, SandboxPageRecord>()
.OrderBy(x => x.Name)
.List()
};
return View(model);
}
public ActionResult Show(int id) {
var page = _contentManager.Get<SandboxPage>(id);
var model = new PageShowViewModel {
Page = _contentManager.Get<SandboxPage>(id)
Page = page,
Displays = _contentManager.GetDisplays(page)
};
model.Displays = _contentManager.GetDisplays(model.Page.ContentItem);
return View(model);
}

View File

@@ -37,9 +37,9 @@ namespace Orchard.Users.Controllers {
public ActionResult Index() {
var model = new UsersIndexViewModel();
var users = _contentManager.Query("user")
.Where<UserRecord>(x => x.UserName != null)
.List<User>();
var users = _contentManager.Query<User,UserRecord>("user")
.Where(x => x.UserName != null)
.List();
model.Rows = users.Select(x => new UsersIndexViewModel.Row {User = x}).ToList();

View File

@@ -63,7 +63,7 @@ namespace Orchard.Environment {
(type.GetProperty("Id").GetAccessors() ?? Enumerable.Empty<MethodInfo>()).All(x => x.IsVirtual) &&
!type.IsSealed &&
!type.IsAbstract &&
!typeof(IContent).IsAssignableFrom(type);
(!typeof(IContent).IsAssignableFrom(type) || typeof(ContentPartRecord).IsAssignableFrom(type));
}
}
}

View File

@@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Orchard.Models.Records;
namespace Orchard.Models {
@@ -33,23 +34,37 @@ namespace Orchard.Models {
}
public static IContentQuery Query(this IContentManager manager, params string[] contentTypeNames) {
return manager.Query().ForType(contentTypeNames);
public static IContentQuery<TPart> Query<TPart>(this IContentManager manager)
where TPart : ContentPart {
return manager.Query().ForPart<TPart>();
}
public static IEnumerable<T> List<T>(this IContentManager manager, params string[] contentTypeNames) where T : class, IContent {
return manager.Query(contentTypeNames).List<T>();
public static IContentQuery<TPart, TRecord> Query<TPart, TRecord>(this IContentManager manager)
where TPart : ContentPart<TRecord>
where TRecord : ContentPartRecord {
return manager.Query().ForPart<TPart>().Join<TRecord>();
}
public static IEnumerable<T> List<T>(this IContentQuery query) where T : class, IContent {
return query.List().AsPart<T>();
public static IContentQuery<ContentItem> Query(this IContentManager manager, params string[] contentTypeNames) {
return manager.Query().ForType(contentTypeNames);
}
public static IEnumerable<T> Slice<T>(this IContentQuery query, int skip, int count) where T : class, IContent {
return query.Slice(skip, count).AsPart<T>();
public static IContentQuery<TPart> Query<TPart>(this IContentManager manager, params string[] contentTypeNames) where TPart : ContentPart {
return manager.Query().ForPart<TPart>().ForType(contentTypeNames);
}
public static IEnumerable<T> Slice<T>(this IContentQuery query, int count) where T : class, IContent {
return query.Slice(0, count).AsPart<T>();
public static IContentQuery<TPart,TRecord> Query<TPart,TRecord>(this IContentManager manager, params string[] contentTypeNames) where TPart : ContentPart<TRecord> where TRecord : ContentPartRecord {
return manager.Query().ForPart<TPart>().ForType(contentTypeNames).Join<TRecord>();
}
public static IEnumerable<ContentItem> Slice(this IContentQuery query, int count) {
public static IEnumerable<T> List<T>(this IContentManager manager, params string[] contentTypeNames) where T : ContentPart {
return manager.Query<T>(contentTypeNames).List();
}
public static IEnumerable<T> List<T>(this IContentQuery query) where T : IContent {
return query.ForPart<T>().List();
}
public static IEnumerable<T> Slice<T>(this IContentQuery<T> query, int count) where T : IContent {
return query.Slice(0, count);
}
@@ -58,19 +73,19 @@ namespace Orchard.Models {
public static bool Is<T>(this IContent content) {
return content == null ? false : content.ContentItem.Has(typeof(T));
}
public static T As<T>(this IContent content) where T : class {
return content == null ? null : (T)content.ContentItem.Get(typeof(T));
public static T As<T>(this IContent content) where T : IContent {
return content == null ? default(T) : (T)content.ContentItem.Get(typeof(T));
}
public static bool Has<T>(this IContent content) {
return content == null ? false : content.ContentItem.Has(typeof(T));
}
public static T Get<T>(this IContent content) where T : class {
return content == null ? null : (T)content.ContentItem.Get(typeof(T));
public static T Get<T>(this IContent content) where T : IContent {
return content == null ? default(T) : (T)content.ContentItem.Get(typeof(T));
}
public static IEnumerable<T> AsPart<T>(this IEnumerable<ContentItem> items) where T : class {
public static IEnumerable<T> AsPart<T>(this IEnumerable<ContentItem> items) where T : IContent {
return items == null ? null : items.Where(item => item.Is<T>()).Select(item => item.As<T>());
}

View File

@@ -21,10 +21,12 @@ namespace Orchard.Models {
public bool Has(Type partType) {
return _parts.Any(part => partType.IsAssignableFrom(part.GetType()));
return partType==typeof(ContentItem) || _parts.Any(part => partType.IsAssignableFrom(part.GetType()));
}
public IContent Get(Type partType) {
if (partType == typeof(ContentItem))
return this;
return _parts.FirstOrDefault(part => partType.IsAssignableFrom(part.GetType()));
}

View File

@@ -1,6 +1,6 @@
namespace Orchard.Models {
public abstract class ContentPart : IContent {
public ContentItem ContentItem { get; set; }
public virtual ContentItem ContentItem { get; set; }
}
public class ContentPart<TRecord> : ContentPart {

View File

@@ -139,8 +139,9 @@ namespace Orchard.Models {
return context.Editors;
}
public IContentQuery Query() {
return _context.Resolve<IContentQuery>(TypedParameter.From<IContentManager>(this));
public IContentQuery<ContentItem> Query() {
var query = _context.Resolve<IContentQuery>(TypedParameter.From<IContentManager>(this));
return query.ForPart<ContentItem>();
}
private ContentTypeRecord AcquireContentTypeRecord(string contentType) {

View File

@@ -46,19 +46,19 @@ namespace Orchard.Models {
}
public IContentQuery ForType(params string[] contentTypeNames) {
private void ForType(params string[] contentTypeNames) {
BindCriteriaByPath("ContentType").Add(Restrictions.InG("Name", contentTypeNames));
return this;
return;
}
public IContentQuery Where<TRecord>() {
private void Where<TRecord>() {
// this simply demands an inner join
BindCriteriaByPath(typeof(TRecord).Name);
return this;
return;
}
public IContentQuery Where<TRecord>(Expression<Func<TRecord, bool>> predicate) {
private void Where<TRecord>(Expression<Func<TRecord, bool>> predicate) {
// build a linq to nhibernate expression
var options = new QueryOptions();
@@ -74,10 +74,10 @@ namespace Orchard.Models {
recordCriteria.Add(expressionEntry.Criterion);
}
return this;
return;
}
public IContentQuery OrderBy<TRecord, TKey>(Expression<Func<TRecord, TKey>> keySelector) {
private void OrderBy<TRecord, TKey>(Expression<Func<TRecord, TKey>> keySelector) {
// build a linq to nhibernate expression
var options = new QueryOptions();
var queryProvider = new NHibernateQueryProvider(BindSession(), options);
@@ -92,10 +92,10 @@ namespace Orchard.Models {
recordCriteria.AddOrder(ordering.Order);
}
return this;
return;
}
public IContentQuery OrderByDescending<TRecord, TKey>(Expression<Func<TRecord, TKey>> keySelector) {
private void OrderByDescending<TRecord, TKey>(Expression<Func<TRecord, TKey>> keySelector) {
// build a linq to nhibernate expression
var options = new QueryOptions();
var queryProvider = new NHibernateQueryProvider(BindSession(), options);
@@ -109,16 +109,16 @@ namespace Orchard.Models {
foreach (var ordering in criteria.IterateOrderings()) {
recordCriteria.AddOrder(ordering.Order);
}
return this;
return;
}
public IEnumerable<ContentItem> List() {
private IEnumerable<ContentItem> List() {
return BindItemCriteria()
.List<ContentItemRecord>()
.Select(x => ContentManager.Get(x.Id));
}
public IEnumerable<ContentItem> Slice(int skip, int count) {
private IEnumerable<ContentItem> Slice(int skip, int count) {
var criteria = BindItemCriteria();
if (skip != 0)
criteria = criteria.SetFirstResult(skip);
@@ -128,5 +128,82 @@ namespace Orchard.Models {
.List<ContentItemRecord>()
.Select(x => ContentManager.Get(x.Id));
}
IContentQuery<TPart> IContentQuery.ForPart<TPart>() {
return new ContentQuery<TPart>(this);
}
class ContentQuery<T> : IContentQuery<T> where T : IContent {
protected readonly DefaultContentQuery _query;
public ContentQuery(DefaultContentQuery query) {
_query = query;
}
public IContentManager ContentManager {
get { return _query.ContentManager; }
}
public IContentQuery<TPart> ForPart<TPart>() where TPart : IContent {
return new ContentQuery<TPart>(_query);
}
public IContentQuery<T> ForType(params string[] contentTypes) {
_query.ForType(contentTypes);
return this;
}
public IEnumerable<T> List() {
return _query.List().AsPart<T>();
}
public IEnumerable<T> Slice(int skip, int count) {
return _query.Slice(skip, count).AsPart<T>();
}
public IContentQuery<T, TRecord> Join<TRecord>() where TRecord : ContentPartRecord {
_query.Where<TRecord>();
return new ContentQuery<T, TRecord>(_query);
}
public IContentQuery<T, TRecord> Where<TRecord>(Expression<Func<TRecord, bool>> predicate) where TRecord : ContentPartRecord {
_query.Where(predicate);
return new ContentQuery<T, TRecord>(_query);
}
public IContentQuery<T, TRecord> OrderBy<TRecord, TKey>(Expression<Func<TRecord, TKey>> keySelector) where TRecord : ContentPartRecord {
_query.OrderBy(keySelector);
return new ContentQuery<T, TRecord>(_query);
}
public IContentQuery<T, TRecord> OrderByDescending<TRecord, TKey>(Expression<Func<TRecord, TKey>> keySelector) where TRecord : ContentPartRecord {
_query.OrderByDescending(keySelector);
return new ContentQuery<T, TRecord>(_query);
}
}
class ContentQuery<T, TR> : ContentQuery<T>, IContentQuery<T, TR>
where T : IContent
where TR : ContentPartRecord {
public ContentQuery(DefaultContentQuery query)
: base(query) {
}
public IContentQuery<T, TR> Where(Expression<Func<TR, bool>> predicate) {
_query.Where(predicate);
return this;
}
public IContentQuery<T, TR> OrderBy<TKey>(Expression<Func<TR, TKey>> keySelector) {
_query.OrderBy(keySelector);
return this;
}
public IContentQuery<T, TR> OrderByDescending<TKey>(Expression<Func<TR, TKey>> keySelector) {
_query.OrderByDescending(keySelector);
return this;
}
}
}
}

View File

@@ -16,7 +16,7 @@ namespace Orchard.Models.Driver {
}
protected override void Creating(CreateContentContext context, ContentPart<TRecord> instance) {
instance.Record.ContentItem = context.ContentItemRecord;
instance.Record.ContentItemRecord = context.ContentItemRecord;
_repository.Create(instance.Record);
}
@@ -26,7 +26,7 @@ namespace Orchard.Models.Driver {
instance.Record = record;
}
else if (AutomaticallyCreateMissingRecord) {
instance.Record = new TRecord {ContentItem = context.ContentItemRecord};
instance.Record = new TRecord {ContentItemRecord = context.ContentItemRecord};
_repository.Create(instance.Record);
}
}

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using Orchard.Models.Driver;
using Orchard.Models.Records;
using Orchard.UI.Models;
namespace Orchard.Models {
@@ -8,7 +9,8 @@ namespace Orchard.Models {
void Create(ContentItem contentItem);
ContentItem Get(int id);
IContentQuery Query();
IContentQuery<ContentItem> Query();
IEnumerable<ModelTemplate> GetDisplays(IContent contentItem);
IEnumerable<ModelTemplate> GetEditors(IContent contentItem);

View File

@@ -1,20 +1,31 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using Orchard.Models.Records;
namespace Orchard.Models {
public interface IContentQuery {
IContentManager ContentManager { get; }
IContentQuery ForType(params string[] contentTypeNames);
IContentQuery Where<TRecord>();
IContentQuery Where<TRecord>(Expression<Func<TRecord, bool>> predicate);
IContentQuery OrderBy<TRecord, TKey>(Expression<Func<TRecord, TKey>> keySelector);
IContentQuery OrderByDescending<TRecord, TKey>(Expression<Func<TRecord, TKey>> keySelector);
IEnumerable<ContentItem> List();
IEnumerable<ContentItem> Slice(int skip, int count);
IContentQuery<TPart> ForPart<TPart>() where TPart : IContent;
}
public interface IContentQuery<TPart> : IContentQuery where TPart : IContent {
IContentQuery<TPart> ForType(params string[] contentTypes);
IEnumerable<TPart> List();
IEnumerable<TPart> Slice(int skip, int count);
IContentQuery<TPart, TRecord> Join<TRecord>() where TRecord : ContentPartRecord;
IContentQuery<TPart, TRecord> Where<TRecord>(Expression<Func<TRecord, bool>> predicate) where TRecord : ContentPartRecord;
IContentQuery<TPart, TRecord> OrderBy<TRecord, TKey>(Expression<Func<TRecord, TKey>> keySelector) where TRecord : ContentPartRecord;
IContentQuery<TPart, TRecord> OrderByDescending<TRecord, TKey>(Expression<Func<TRecord, TKey>> keySelector) where TRecord : ContentPartRecord;
}
public interface IContentQuery<TPart, TRecord> : IContentQuery<TPart> where TPart : IContent where TRecord : ContentPartRecord {
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);
}
}

View File

@@ -1,6 +1,6 @@
namespace Orchard.Models.Records {
public abstract class ContentPartRecord {
public abstract class ContentPartRecord : ContentPart {
public virtual int Id { get; set; }
public virtual ContentItemRecord ContentItem { get; set; }
public virtual ContentItemRecord ContentItemRecord { get; set; }
}
}

View File

@@ -27,8 +27,9 @@ namespace Orchard.Models.Records {
class Alteration<T> : IAlteration where T : ContentPartRecord {
public void Override(object mappingObj) {
var mapping = (AutoMapping<T>)mappingObj;
mapping.Id(x => x.Id).GeneratedBy.Foreign("ContentItem");
mapping.HasOne(x => x.ContentItem).Constrained();
mapping.Id(x => x.Id).GeneratedBy.Foreign("ContentItemRecord");
mapping.HasOne(x => x.ContentItemRecord).Constrained();
mapping.IgnoreProperty(x => x.ContentItem);
}
}
}