Adding versioning support to content query api

--HG--
extra : convert_revision : svn%3A5ff7c347-ad56-4c35-b696-ccb81de16e03/trunk%4044809
This commit is contained in:
loudej
2009-12-31 02:14:11 +00:00
parent 6a26683cbe
commit 7594a1b656
25 changed files with 776 additions and 337 deletions

View File

@@ -29,6 +29,7 @@ namespace Orchard.Tests.ContentManagement {
databaseFileName,
typeof(GammaRecord),
typeof(DeltaRecord),
typeof(EpsilonRecord),
typeof(ContentItemVersionRecord),
typeof(ContentItemRecord),
typeof(ContentTypeRecord));
@@ -51,6 +52,7 @@ namespace Orchard.Tests.ContentManagement {
builder.Register<BetaHandler>().As<IContentHandler>();
builder.Register<GammaHandler>().As<IContentHandler>();
builder.Register<DeltaHandler>().As<IContentHandler>();
builder.Register<EpsilonHandler>().As<IContentHandler>();
builder.Register<FlavoredHandler>().As<IContentHandler>();
builder.Register<StyledHandler>().As<IContentHandler>();
@@ -61,6 +63,7 @@ namespace Orchard.Tests.ContentManagement {
_session.Delete("from GammaRecord");
_session.Delete("from DeltaRecord");
_session.Delete("from EpsilonRecord");
_session.Delete("from ContentItemVersionRecord");
_session.Delete("from ContentItemRecord");
_session.Delete("from ContentTypeRecord");
@@ -233,6 +236,206 @@ namespace Orchard.Tests.ContentManagement {
Assert.That(subset.Skip(2).First().Id, Is.EqualTo(reverseById.Skip(4).First().Id));
}
[Test]
public void QueryShouldJoinVersionedRecords() {
AddSampleData();
_manager.Create<Gamma>("gamma", init => {
init.Record.Frap = "one";
init.As<Epsilon>().Record.Quad = "1";
});
_manager.Create<Gamma>("gamma", init => {
init.Record.Frap = "two";
init.As<Epsilon>().Record.Quad = "2";
});
_manager.Create<Gamma>("gamma", init => {
init.Record.Frap = "three";
init.As<Epsilon>().Record.Quad = "3";
});
_manager.Create<Gamma>("gamma", init => {
init.Record.Frap = "four";
init.As<Epsilon>().Record.Quad = "4";
});
_session.Flush();
_session.Clear();
var results = _manager.Query<Epsilon, EpsilonRecord>()
.Where(x => x.Quad == "2" || x.Quad == "3")
.OrderByDescending(x => x.Quad)
.List();
Assert.That(results.Count(), Is.EqualTo(2));
Assert.That(results.First().Record, Has.Property("Quad").EqualTo("3"));
Assert.That(results.Last().Record, Has.Property("Quad").EqualTo("2"));
}
private void AddGammaVersions() {
var gamma1 = _manager.Create<ContentItem>("gamma", init => {
init.As<Gamma>().Record.Frap = "one";
init.As<Epsilon>().Record.Quad = "v1";
});
_session.Flush();
_session.Clear();
var gamma2 = _manager.Get(gamma1.Id, VersionOptions.DraftRequired);
gamma2.As<Gamma>().Record.Frap = "two";
gamma2.As<Epsilon>().Record.Quad = "v2";
_session.Flush();
_session.Clear();
var gamma3 = _manager.Create<ContentItem>("gamma", init => {
init.As<Gamma>().Record.Frap = "three";
init.As<Epsilon>().Record.Quad = "v3";
});
_session.Flush();
_session.Clear();
}
[Test]
public void QueryShouldOnlyReturnPublishedByDefault() {
AddGammaVersions();
var list1 = _manager.Query<Gamma>()
.Where<EpsilonRecord>(x => x.Quad == "v1")
.List();
var list2 = _manager.Query<Gamma>()
.Where<EpsilonRecord>(x => x.Quad == "v2")
.List();
var list3 = _manager.Query<Gamma>()
.Where<EpsilonRecord>(x => x.Quad == "v3")
.List();
var listOne = _manager.Query<Gamma>()
.Where<GammaRecord>(x => x.Frap == "one")
.List();
var listTwo = _manager.Query<Gamma>()
.Where<GammaRecord>(x => x.Frap == "two")
.List();
var listThree = _manager.Query<Gamma>()
.Where<GammaRecord>(x => x.Frap == "three")
.List();
Assert.That(list1.Count(), Is.EqualTo(1));
Assert.That(list2.Count(), Is.EqualTo(0));
Assert.That(list3.Count(), Is.EqualTo(1));
Assert.That(listOne.Count(), Is.EqualTo(0));
Assert.That(listTwo.Count(), Is.EqualTo(1));
Assert.That(listThree.Count(), Is.EqualTo(1));
}
[Test]
public void QueryForLatestShouldNotReturnEarlierVersions() {
AddGammaVersions();
var list1 = _manager.Query<Gamma>(VersionOptions.Latest)
.Where<EpsilonRecord>(x => x.Quad == "v1")
.List();
var list2 = _manager.Query<Gamma>(VersionOptions.Latest)
.Where<EpsilonRecord>(x => x.Quad == "v2")
.List();
var list3 = _manager.Query<Gamma>(VersionOptions.Latest)
.Where<EpsilonRecord>(x => x.Quad == "v3")
.List();
var listOne = _manager.Query<Gamma>(VersionOptions.Latest)
.Where<GammaRecord>(x => x.Frap == "one")
.List();
var listTwo = _manager.Query<Gamma>(VersionOptions.Latest)
.Where<GammaRecord>(x => x.Frap == "two")
.List();
var listThree = _manager.Query<Gamma>(VersionOptions.Latest)
.Where<GammaRecord>(x => x.Frap == "three")
.List();
Assert.That(list1.Count(), Is.EqualTo(0));
Assert.That(list2.Count(), Is.EqualTo(1));
Assert.That(list3.Count(), Is.EqualTo(1));
Assert.That(listOne.Count(), Is.EqualTo(0));
Assert.That(listTwo.Count(), Is.EqualTo(1));
Assert.That(listThree.Count(), Is.EqualTo(1));
}
[Test]
public void QueryForDraftShouldOnlyReturnLatestThatIsNotPublished() {
AddGammaVersions();
var list1 = _manager.Query<Gamma>(VersionOptions.Draft)
.Where<EpsilonRecord>(x => x.Quad == "v1")
.List();
var list2 = _manager.Query<Gamma>(VersionOptions.Draft)
.Where<EpsilonRecord>(x => x.Quad == "v2")
.List();
var list3 = _manager.Query<Gamma>(VersionOptions.Draft)
.Where<EpsilonRecord>(x => x.Quad == "v3")
.List();
var listOne = _manager.Query<Gamma>(VersionOptions.Draft)
.Where<GammaRecord>(x => x.Frap == "one")
.List();
var listTwo = _manager.Query<Gamma>(VersionOptions.Draft)
.Where<GammaRecord>(x => x.Frap == "two")
.List();
var listThree = _manager.Query<Gamma>(VersionOptions.Draft)
.Where<GammaRecord>(x => x.Frap == "three")
.List();
Assert.That(list1.Count(), Is.EqualTo(0));
Assert.That(list2.Count(), Is.EqualTo(1));
Assert.That(list3.Count(), Is.EqualTo(0));
Assert.That(listOne.Count(), Is.EqualTo(0));
Assert.That(listTwo.Count(), Is.EqualTo(1));
Assert.That(listThree.Count(), Is.EqualTo(0));
}
[Test]
public void QueryForAllShouldReturnMultipleQualifiedVersions() {
AddGammaVersions();
var list1 = _manager.Query<Gamma>(VersionOptions.AllVersions)
.Where<EpsilonRecord>(x => x.Quad == "v1")
.List();
var list2 = _manager.Query<Gamma>(VersionOptions.AllVersions)
.Where<EpsilonRecord>(x => x.Quad == "v2")
.List();
var list3 = _manager.Query<Gamma>(VersionOptions.AllVersions)
.Where<EpsilonRecord>(x => x.Quad == "v3")
.List();
var listOne = _manager.Query<Gamma>(VersionOptions.AllVersions)
.Where<GammaRecord>(x => x.Frap == "one")
.List();
var listTwo = _manager.Query<Gamma>(VersionOptions.AllVersions)
.Where<GammaRecord>(x => x.Frap == "two")
.List();
var listThree = _manager.Query<Gamma>(VersionOptions.AllVersions)
.Where<GammaRecord>(x => x.Frap == "three")
.List();
Assert.That(list1.Count(), Is.EqualTo(1));
Assert.That(list2.Count(), Is.EqualTo(1));
Assert.That(list3.Count(), Is.EqualTo(1));
Assert.That(listOne.Count(), Is.EqualTo(0));
Assert.That(listTwo.Count(), Is.EqualTo(2));
Assert.That(listThree.Count(), Is.EqualTo(1));
}
}
}

View File

@@ -409,6 +409,56 @@ namespace Orchard.Tests.ContentManagement {
Assert.That(epsilon1.ContentItem.VersionRecord, Is.Not.SameAs(epsilon2.ContentItem.VersionRecord));
Assert.That(epsilon1B.ContentItem.VersionRecord, Is.Not.SameAs(epsilon2B.ContentItem.VersionRecord));
}
private void Flush() {
Trace.WriteLine("flush");
_session.Flush();
}
private void FlushAndClear() {
Trace.WriteLine("flush");
_session.Flush();
Trace.WriteLine("clear");
_session.Clear();
}
[Test]
public void GetAllVersionsShouldReturnHistoryInOrder() {
Trace.WriteLine("gamma1");
var gamma1 = _manager.Create("gamma", VersionOptions.Published);
Flush();
Trace.WriteLine("gamma2");
var gamma2 = _manager.GetDraftRequired(gamma1.Id);
Trace.WriteLine("publish");
_manager.Publish(gamma2);
Flush();
Trace.WriteLine("gamma3");
var gamma3 = _manager.GetDraftRequired(gamma1.Id);
Trace.WriteLine("publish");
_manager.Publish(gamma3);
Flush();
Trace.WriteLine("gamma4");
var gamma4 = _manager.GetDraftRequired(gamma1.Id);
Trace.WriteLine("publish");
_manager.Publish(gamma2);
FlushAndClear();
Assert.That(gamma1.Version, Is.EqualTo(1));
Assert.That(gamma2.Version, Is.EqualTo(2));
Assert.That(gamma3.Version, Is.EqualTo(3));
Assert.That(gamma4.Version, Is.EqualTo(4));
var gammas = _manager.GetAllVersions(gamma1.Id).ToList();
Assert.That(gammas[0].Version, Is.EqualTo(1));
Assert.That(gammas[1].Version, Is.EqualTo(2));
Assert.That(gammas[2].Version, Is.EqualTo(3));
Assert.That(gammas[3].Version, Is.EqualTo(4));
}
}
}

View File

@@ -166,13 +166,12 @@ namespace Orchard.Tests.Data {
}
[Test]
public void RepositoryCanCreateFetchUpdateAndDelete() {
public void RepositoryCanCreateFetchAndDelete() {
var foo1 = new Foo { Name = "yadda" };
_fooRepos.Create(foo1);
var foo2 = _fooRepos.Get(foo1.Id);
foo2.Name = "blah";
_fooRepos.Update(foo2);
Assert.That(foo1, Is.SameAs(foo2));

View File

@@ -28,9 +28,9 @@ namespace Orchard.DevTools.Controllers {
});
}
public ActionResult Details(int id) {
public ActionResult Details(int id, int? version) {
var model = new ContentDetailsViewModel {
Item = _contentManager.Get(id)
Item = version == null ? _contentManager.Get(id) : _contentManager.Get(id, VersionOptions.Number((int)version))
};
model.PartTypes = model.Item.ContentItem.Parts
.Select(x => x.GetType())
@@ -42,6 +42,8 @@ namespace Orchard.DevTools.Controllers {
return View(model);
}
static IEnumerable<Type> AllTypes(Type type) {
var scan = type;
while (scan != null && scan != typeof(Object) && scan != typeof(ContentPart)) {

View File

@@ -4,9 +4,16 @@
<h1><%=Html.TitleForPage(string.Format("{0} Content Type", Model.Item.ContentItem.ContentType), "Content")%></h1>
<h3>Content Item</h3>
<p>Id:
<%=Model.Item.ContentItem.Id %></p>
<p>ContentType:
<%=Model.Item.ContentItem.ContentType%> <%=Html.ItemDisplayLink(Model.Item) %> <%=Html.ItemEditLink("edit", Model.Item) %></p>
<%=Model.Item.ContentItem.Id %><br />
Version:
<%=Model.Item.ContentItem.Version %><br />
ContentType:
<%=Model.Item.ContentItem.ContentType%> <br />
DisplayText:
<%=Html.ItemDisplayText(Model.Item) %><br />
Links:
<%=Html.ItemDisplayLink("view", Model.Item) %> <%=Html.ItemEditLink("edit", Model.Item) %></p>
<h3>Content Item Parts</h3>
<ul>
<%foreach (var partType in Model.PartTypes.OrderBy(x => x.Name)) {%>

View File

@@ -2,4 +2,4 @@
<%@ Import Namespace="Orchard.DevTools.Models" %>
<div class="debug message">
DevTools: showing
<%= Html.ActionLink(Model.ContentItem.ContentType + " #" + Model.ContentItem.Id, "details", "content", new { area = "Orchard.DevTools", Model.ContentItem.Id }, new { })%></div>
<%= Html.ActionLink(Model.ContentItem.ContentType + " #" + Model.ContentItem.Id + " v" + Model.ContentItem.Version, "details", "content", new { area = "Orchard.DevTools", Model.ContentItem.Id, Model.ContentItem.Version }, new { })%></div>

View File

@@ -3,5 +3,5 @@
<% if (Model.ContentItem.Id > 0) { %>
<div class="debug message">
DevTools: editing
<%= Html.ActionLink(Model.ContentItem.ContentType + " #" + Model.ContentItem.Id, "details", "content", new { area = "Orchard.DevTools", Model.ContentItem.Id }, new { })%></div>
<%= Html.ActionLink(Model.ContentItem.ContentType + " #" + Model.ContentItem.Id + " v" + Model.ContentItem.Version, "details", "content", new { area = "Orchard.DevTools", Model.ContentItem.Id, Model.ContentItem.Version }, new { })%></div>
<% } %>

View File

@@ -68,8 +68,9 @@ namespace Orchard.Sandbox.Controllers {
return RedirectToAction("show", new { id });
}
var latest = Services.ContentManager.GetLatest<SandboxPage>(id);
return View(new PageEditViewModel {
Page = Services.ContentManager.BuildEditorModel<SandboxPage>(id)
Page = Services.ContentManager.BuildEditorModel(latest)
});
}
@@ -78,15 +79,15 @@ namespace Orchard.Sandbox.Controllers {
if (IsEditAllowed() == false) {
return RedirectToAction("show", new { id });
}
var latest = Services.ContentManager.GetDraftRequired<SandboxPage>(id);
var model = new PageEditViewModel {
Page = Services.ContentManager.UpdateEditorModel<SandboxPage>(id, this)
Page = Services.ContentManager.UpdateEditorModel(latest, this)
};
if (!ModelState.IsValid) {
Services.TransactionManager.Cancel();
return View(model);
}
Services.ContentManager.Publish(latest.ContentItem);
return RedirectToAction("show", new { id });
}

View File

@@ -60,19 +60,93 @@ namespace Orchard.ContentManagement {
}
}
public static class ContentExtensions {
public static class ContentQueryExtensions {
/* Query related extension methods */
public static IContentQuery<TPart> Query<TPart>(this IContentManager manager)
where TPart : ContentPart {
return manager.Query().ForPart<TPart>();
}
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>();
}
/* Query(VersionOptions options) */
public static IContentQuery<ContentItem> Query(this IContentManager manager, VersionOptions options) {
return manager.Query().ForVersion(options);
}
public static IContentQuery<TPart> Query<TPart>(this IContentManager manager, VersionOptions options) where TPart : ContentPart {
return manager.Query().ForPart<TPart>().ForVersion(options);
}
public static IContentQuery<TPart, TRecord> Query<TPart, TRecord>(this IContentManager manager, VersionOptions options)
where TPart : ContentPart<TRecord>
where TRecord : ContentPartRecord {
return manager.Query().ForPart<TPart>().ForVersion(options).Join<TRecord>();
}
/* Query(params string[] contentTypeNames) */
public static IContentQuery<ContentItem> Query(this IContentManager manager, params string[] contentTypeNames) {
return manager.Query().ForType(contentTypeNames);
}
public static IContentQuery<TPart> Query<TPart>(this IContentManager manager, params string[] contentTypeNames) where TPart : ContentPart {
return manager.Query().ForPart<TPart>().ForType(contentTypeNames);
}
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<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);
}
}
public static class ContentGetExtensions {
public static ContentItem GetLatest(this IContentManager manager, int id) {
return manager.Get(id, VersionOptions.Latest);
}
public static ContentItem GetDraftRequired(this IContentManager manager, int id) {
return manager.Get(id, VersionOptions.DraftRequired);
}
public static T Get<T>(this IContentManager manager, int id) where T : class, IContent {
var contentItem = manager.Get(id);
return contentItem == null ? null : contentItem.Get<T>();
}
public static T Get<T>(this IContentManager manager, int id, VersionOptions options) where T : class, IContent {
var contentItem = manager.Get(id, options);
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);
}
public static T GetDraftRequired<T>(this IContentManager manager, int id) where T : class, IContent {
return Get<T>(manager, id, VersionOptions.DraftRequired);
}
}
public static class ContentExtensions {
/* Display and editor convenience extension methods */
@@ -90,41 +164,6 @@ namespace Orchard.ContentManagement {
}
/* Query related extension methods */
public static IContentQuery<TPart> Query<TPart>(this IContentManager manager)
where TPart : ContentPart {
return manager.Query().ForPart<TPart>();
}
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 IContentQuery<ContentItem> Query(this IContentManager manager, params string[] contentTypeNames) {
return manager.Query().ForType(contentTypeNames);
}
public static IContentQuery<TPart> Query<TPart>(this IContentManager manager, params string[] contentTypeNames) where TPart : ContentPart {
return manager.Query().ForPart<TPart>().ForType(contentTypeNames);
}
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<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);
}
/* Aggregate item/part type casting extension methods */

View File

@@ -84,6 +84,7 @@ namespace Orchard.ContentManagement {
versionRecord = _contentItemVersionRepository.Get(options.VersionRecordId);
}
else {
// FIX: rework this so it falls back to an in-memory scan when the results don't fit the criteria
var record = _contentItemRepository.Get(id);
if (options.IsPublished) {
versionRecord = _contentItemVersionRepository.Get(x => x.ContentItemRecord == record && x.Published);
@@ -143,13 +144,47 @@ namespace Orchard.ContentManagement {
// when draft is required and not currently available a new version is appended
if (appendLatestVersion) {
return AppendLatestVersion(context.ContentItem);
return BuildNewVersion(context.ContentItem);
}
return context.ContentItem;
}
public virtual ContentItem AppendLatestVersion(ContentItem existingContentItem) {
public virtual IEnumerable<ContentItem> GetAllVersions(int id) {
return _contentItemVersionRepository
.Fetch(x => x.ContentItemRecord.Id == id)
.OrderBy(x => x.Number)
.Select(x => Get(x.ContentItemRecord.Id, VersionOptions.VersionRecord(x.Id)));
}
public virtual void Publish(ContentItem contentItem) {
if (contentItem.VersionRecord.Published) {
return;
}
var previous = contentItem.Record.Versions.SingleOrDefault(x => x.Published);
if (previous != null) {
previous.Published = false;
//_contentItemVersionRepository.Update(previous);
}
contentItem.VersionRecord.Published = true;
//_contentItemVersionRepository.Update(contentItem.VersionRecord);
//TODO: fire content handler events
}
public virtual void Remove(ContentItem contentItem) {
var activeVersions = _contentItemVersionRepository.Fetch(x => x.ContentItemRecord == contentItem.Record && (x.Published || x.Latest));
foreach (var version in activeVersions) {
if (version.Published) {
version.Published = false;
}
if (version.Latest) {
version.Latest = false;
}
}
//TODO: fire content handler events
}
protected virtual ContentItem BuildNewVersion(ContentItem existingContentItem) {
var contentItemRecord = existingContentItem.Record;
// locate the existing and the current latest versions, allocate building version
@@ -160,17 +195,18 @@ namespace Orchard.ContentManagement {
Published = false
};
if (existingItemVersionRecord.Latest == false) {
var latestVersion = _contentItemVersionRepository.Get(x => x.ContentItemRecord == contentItemRecord && x.Latest);
var latestVersion = contentItemRecord.Versions.SingleOrDefault(x => x.Latest);
if (latestVersion != null) {
latestVersion.Latest = false;
buildingItemVersionRecord.Number = latestVersion.Number + 1;
}
else {
existingItemVersionRecord.Latest = false;
buildingItemVersionRecord.Number = existingItemVersionRecord.Number + 1;
buildingItemVersionRecord.Number = contentItemRecord.Versions.Max(x => x.Number) + 1;
}
contentItemRecord.Versions.Add(buildingItemVersionRecord);
_contentItemVersionRepository.Create(buildingItemVersionRecord);
var buildingContentItem = New(existingContentItem.ContentType);

View File

@@ -8,12 +8,14 @@ using NHibernate.Impl;
using NHibernate.Linq;
using Orchard.ContentManagement.Records;
using Orchard.Data;
using Orchard.Utility;
namespace Orchard.ContentManagement {
public class DefaultContentQuery : IContentQuery {
private readonly ISessionLocator _sessionLocator;
private ISession _session;
private ICriteria _itemCriteria;
private ICriteria _itemVersionCriteria;
private VersionOptions _versionOptions;
public DefaultContentQuery(IContentManager contentManager, ISessionLocator sessionLocator) {
_sessionLocator = sessionLocator;
@@ -24,41 +26,53 @@ namespace Orchard.ContentManagement {
ISession BindSession() {
if (_session == null)
_session = _sessionLocator.For(typeof(ContentItemRecord));
_session = _sessionLocator.For(typeof(ContentItemVersionRecord));
return _session;
}
ICriteria BindCriteriaByPath(ICriteria criteria, string path) {
return criteria.GetCriteriaByPath(path) ?? criteria.CreateCriteria(path);
}
ICriteria BindTypeCriteria() {
return BindCriteriaByPath(BindCriteriaByPath(BindItemVersionCriteria(), "ContentItemRecord"), "ContentType");
}
ICriteria BindItemCriteria() {
if (_itemCriteria == null) {
_itemCriteria = BindSession().CreateCriteria<ContentItemRecord>();
}
return _itemCriteria;
return BindCriteriaByPath(BindItemVersionCriteria(), "ContentItemRecord");
}
ICriteria BindCriteriaByPath(string path) {
var itemCriteria = BindItemCriteria();
ICriteria BindItemVersionCriteria() {
if (_itemVersionCriteria == null) {
_itemVersionCriteria = BindSession().CreateCriteria<ContentItemVersionRecord>();
}
return _itemVersionCriteria;
}
// special if the content item is ever used as where or order
if (path == typeof(ContentItemRecord).Name)
return itemCriteria;
return itemCriteria.GetCriteriaByPath(path) ?? itemCriteria.CreateCriteria(path);
ICriteria BindPartCriteria<TRecord>() where TRecord : ContentPartRecord {
if (typeof(TRecord).IsSubclassOf(typeof(ContentPartVersionRecord))) {
return BindCriteriaByPath(BindItemVersionCriteria(), typeof(TRecord).Name);
}
return BindCriteriaByPath(BindItemCriteria(), typeof(TRecord).Name);
}
private void ForType(params string[] contentTypeNames) {
BindCriteriaByPath("ContentType").Add(Restrictions.InG("Name", contentTypeNames));
return;
if (contentTypeNames != null && contentTypeNames.Length != 0)
BindTypeCriteria().Add(Restrictions.InG("Name", contentTypeNames));
}
public void ForVersion(VersionOptions options) {
_versionOptions = options;
}
private void Where<TRecord>() {
private void Where<TRecord>() where TRecord : ContentPartRecord {
// this simply demands an inner join
BindCriteriaByPath(typeof(TRecord).Name);
return;
BindPartCriteria<TRecord>();
}
private void Where<TRecord>(Expression<Func<TRecord, bool>> predicate) {
private void Where<TRecord>(Expression<Func<TRecord, bool>> predicate) where TRecord : ContentPartRecord {
// build a linq to nhibernate expression
var options = new QueryOptions();
@@ -69,15 +83,13 @@ namespace Orchard.ContentManagement {
var criteria = (CriteriaImpl)queryProvider.TranslateExpression(queryable.Expression);
// attach the criterion from the predicate to this query's criteria for the record
var recordCriteria = BindCriteriaByPath(typeof(TRecord).Name);
var recordCriteria = BindPartCriteria<TRecord>();
foreach (var expressionEntry in criteria.IterateExpressionEntries()) {
recordCriteria.Add(expressionEntry.Criterion);
}
return;
}
private void OrderBy<TRecord, TKey>(Expression<Func<TRecord, TKey>> keySelector) {
private void OrderBy<TRecord, TKey>(Expression<Func<TRecord, TKey>> keySelector) where TRecord : ContentPartRecord {
// build a linq to nhibernate expression
var options = new QueryOptions();
var queryProvider = new NHibernateQueryProvider(BindSession(), options);
@@ -87,15 +99,13 @@ namespace Orchard.ContentManagement {
var criteria = (CriteriaImpl)queryProvider.TranslateExpression(queryable.Expression);
// attaching orderings to the query's criteria
var recordCriteria = BindCriteriaByPath(typeof(TRecord).Name);
var recordCriteria = BindPartCriteria<TRecord>();
foreach (var ordering in criteria.IterateOrderings()) {
recordCriteria.AddOrder(ordering.Order);
}
return;
}
private void OrderByDescending<TRecord, TKey>(Expression<Func<TRecord, TKey>> keySelector) {
private void OrderByDescending<TRecord, TKey>(Expression<Func<TRecord, TKey>> keySelector) where TRecord : ContentPartRecord {
// build a linq to nhibernate expression
var options = new QueryOptions();
var queryProvider = new NHibernateQueryProvider(BindSession(), options);
@@ -105,28 +115,48 @@ namespace Orchard.ContentManagement {
var criteria = (CriteriaImpl)queryProvider.TranslateExpression(queryable.Expression);
// attaching orderings to the query's criteria
var recordCriteria = BindCriteriaByPath(typeof(TRecord).Name);
var recordCriteria = BindPartCriteria<TRecord>();
foreach (var ordering in criteria.IterateOrderings()) {
recordCriteria.AddOrder(ordering.Order);
}
return;
}
private IEnumerable<ContentItem> List() {
return BindItemCriteria()
.List<ContentItemRecord>()
.Select(x => ContentManager.Get(x.Id));
}
private IEnumerable<ContentItem> Slice(int skip, int count) {
var criteria = BindItemCriteria();
if (skip != 0)
var criteria = BindItemVersionCriteria();
if (_versionOptions == null) {
criteria.Add(Restrictions.Eq("Published", true));
}
else if (_versionOptions.IsPublished) {
criteria.Add(Restrictions.Eq("Published", true));
}
else if (_versionOptions.IsLatest) {
criteria.Add(Restrictions.Eq("Latest", true));
}
else if (_versionOptions.IsDraft) {
criteria.Add(Restrictions.And(
Restrictions.Eq("Latest", true),
Restrictions.Eq("Published", false)));
}
else if (_versionOptions.IsAllVersions) {
// no-op... all versions will be returned by default
}
else {
throw new ApplicationException("Invalid VersionOptions for content query");
}
// TODO: put 'removed false' filter in place
if (skip != 0) {
criteria = criteria.SetFirstResult(skip);
if (count != 0)
}
if (count != 0) {
criteria = criteria.SetMaxResults(count);
}
return criteria
.List<ContentItemRecord>()
.Select(x => ContentManager.Get(x.Id));
.List<ContentItemVersionRecord>()
.Select(x => ContentManager.Get(x.Id, VersionOptions.VersionRecord(x.Id)))
.ToReadOnlyCollection();
}
IContentQuery<TPart> IContentQuery.ForPart<TPart>() {
@@ -144,44 +174,50 @@ namespace Orchard.ContentManagement {
get { return _query.ContentManager; }
}
public IContentQuery<TPart> ForPart<TPart>() where TPart : IContent {
IContentQuery<TPart> IContentQuery.ForPart<TPart>() {
return new ContentQuery<TPart>(_query);
}
public IContentQuery<T> ForType(params string[] contentTypes) {
IContentQuery<T> IContentQuery<T>.ForType(params string[] contentTypes) {
_query.ForType(contentTypes);
return this;
}
public IEnumerable<T> List() {
return _query.List().AsPart<T>();
IContentQuery<T> IContentQuery<T>.ForVersion(VersionOptions options) {
_query.ForVersion(options);
return this;
}
public IEnumerable<T> Slice(int skip, int count) {
IEnumerable<T> IContentQuery<T>.List() {
return _query.Slice(0, 0).AsPart<T>();
}
IEnumerable<T> IContentQuery<T>.Slice(int skip, int count) {
return _query.Slice(skip, count).AsPart<T>();
}
public IContentQuery<T, TRecord> Join<TRecord>() where TRecord : ContentPartRecord {
IContentQuery<T, TRecord> IContentQuery<T>.Join<TRecord>() {
_query.Where<TRecord>();
return new ContentQuery<T, TRecord>(_query);
}
public IContentQuery<T, TRecord> Where<TRecord>(Expression<Func<TRecord, bool>> predicate) where TRecord : ContentPartRecord {
IContentQuery<T, TRecord> IContentQuery<T>.Where<TRecord>(Expression<Func<TRecord, bool>> predicate) {
_query.Where(predicate);
return new ContentQuery<T, TRecord>(_query);
}
public IContentQuery<T, TRecord> OrderBy<TRecord, TKey>(Expression<Func<TRecord, TKey>> keySelector) where TRecord : ContentPartRecord {
IContentQuery<T, TRecord> IContentQuery<T>.OrderBy<TRecord, TKey>(Expression<Func<TRecord, TKey>> keySelector) {
_query.OrderBy(keySelector);
return new ContentQuery<T, TRecord>(_query);
}
public IContentQuery<T, TRecord> OrderByDescending<TRecord, TKey>(Expression<Func<TRecord, TKey>> keySelector) where TRecord : ContentPartRecord {
IContentQuery<T, TRecord> IContentQuery<T>.OrderByDescending<TRecord, TKey>(Expression<Func<TRecord, TKey>> keySelector) {
_query.OrderByDescending(keySelector);
return new ContentQuery<T, TRecord>(_query);
}
}
class ContentQuery<T, TR> : ContentQuery<T>, IContentQuery<T, TR>
where T : IContent
where TR : ContentPartRecord {
@@ -189,17 +225,22 @@ namespace Orchard.ContentManagement {
: base(query) {
}
public IContentQuery<T, TR> Where(Expression<Func<TR, bool>> predicate) {
IContentQuery<T, TR> IContentQuery<T, TR>.ForVersion(VersionOptions options) {
_query.ForVersion(options);
return this;
}
IContentQuery<T, TR> 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) {
IContentQuery<T, TR> 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) {
IContentQuery<T, TR> IContentQuery<T, TR>.OrderByDescending<TKey>(Expression<Func<TR, TKey>> keySelector) {
_query.OrderByDescending(keySelector);
return this;
}

View File

@@ -2,7 +2,7 @@ using Orchard.ContentManagement.Records;
using Orchard.Data;
namespace Orchard.ContentManagement.Handlers {
public class StorageFilter<TRecord> : StorageFilterBase<ContentPart<TRecord>> where TRecord : ContentPartRecord,new() {
public class StorageFilter<TRecord> : StorageFilterBase<ContentPart<TRecord>> where TRecord : ContentPartRecord, new() {
private readonly IRepository<TRecord> _repository;
public StorageFilter(IRepository<TRecord> repository) {

View File

@@ -12,8 +12,10 @@ namespace Orchard.ContentManagement {
ContentItem Get(int id);
ContentItem Get(int id, VersionOptions options);
IEnumerable<ContentItem> GetAllVersions(int id);
ContentItem AppendLatestVersion(ContentItem sourceVersion);
void Publish(ContentItem contentItem);
void Remove(ContentItem contentItem);
IContentQuery<ContentItem> Query();
@@ -29,6 +31,7 @@ namespace Orchard.ContentManagement {
public static VersionOptions Published { get { return new VersionOptions { IsPublished = true }; } }
public static VersionOptions Draft { get { return new VersionOptions { IsDraft = true }; } }
public static VersionOptions DraftRequired { get { return new VersionOptions { IsDraft = true, IsDraftRequired = true }; } }
public static VersionOptions AllVersions { get { return new VersionOptions { IsAllVersions = true }; } }
public static VersionOptions Number(int version) { return new VersionOptions { VersionNumber = version }; }
public static VersionOptions VersionRecord(int id) { return new VersionOptions { VersionRecordId = id }; }
@@ -36,6 +39,7 @@ namespace Orchard.ContentManagement {
public bool IsPublished { get; private set; }
public bool IsDraft { get; private set; }
public bool IsDraftRequired { get; private set; }
public bool IsAllVersions { get; private set; }
public int VersionNumber { get; private set; }
public int VersionRecordId { get; private set; }
}

View File

@@ -12,6 +12,8 @@ namespace Orchard.ContentManagement {
public interface IContentQuery<TPart> : IContentQuery where TPart : IContent {
IContentQuery<TPart> ForType(params string[] contentTypes);
IContentQuery<TPart> ForVersion(VersionOptions options);
IEnumerable<TPart> List();
IEnumerable<TPart> Slice(int skip, int count);
@@ -23,9 +25,12 @@ namespace Orchard.ContentManagement {
}
public interface IContentQuery<TPart, TRecord> : IContentQuery<TPart> where TPart : IContent where TRecord : ContentPartRecord {
new IContentQuery<TPart, TRecord> ForVersion(VersionOptions options);
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

@@ -0,0 +1,193 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using FluentNHibernate.Automapping;
using FluentNHibernate.Automapping.Alterations;
using JetBrains.Annotations;
namespace Orchard.ContentManagement.Records {
class ContentItemAlteration : IAutoMappingAlteration {
private readonly IEnumerable<Type> _recordTypes;
[UsedImplicitly]
public ContentItemAlteration() {
_recordTypes = Enumerable.Empty<Type>();
}
public ContentItemAlteration(IEnumerable<Type> recordTypes) {
_recordTypes = recordTypes;
}
public void Alter(AutoPersistenceModel model) {
model.Override<ContentItemRecord>(mapping => {
foreach (var recordType in _recordTypes.Where(Utility.IsPartRecord)) {
var type = typeof(Alteration<,>).MakeGenericType(typeof(ContentItemRecord), recordType);
var alteration = (IAlteration<ContentItemRecord>)Activator.CreateInstance(type);
alteration.Override(mapping);
}
});
model.Override<ContentItemVersionRecord>(mapping => {
foreach (var recordType in _recordTypes.Where(Utility.IsPartVersionRecord)) {
var type = typeof(Alteration<,>).MakeGenericType(typeof(ContentItemVersionRecord), recordType);
var alteration = (IAlteration<ContentItemVersionRecord>)Activator.CreateInstance(type);
alteration.Override(mapping);
}
});
}
interface IAlteration<TItemRecord> {
void Override(AutoMapping<TItemRecord> mapping);
}
class Alteration<TItemRecord, TPartRecord> : IAlteration<TItemRecord> {
public void Override(AutoMapping<TItemRecord> mapping) {
// public TPartRecord TPartRecord {get;set;}
var name = typeof(TPartRecord).Name;
var syntheticMethod = new DynamicMethod(name, typeof(TPartRecord), null, typeof(TItemRecord));
var syntheticProperty = new SyntheticPropertyInfo(syntheticMethod);
// record => record.TPartRecord
var parameter = Expression.Parameter(typeof(TItemRecord), "record");
var syntheticExpression = (Expression<Func<TItemRecord, TPartRecord>>)Expression.Lambda(
typeof(Func<TItemRecord, TPartRecord>),
Expression.Property(parameter, syntheticProperty),
parameter);
mapping.References(syntheticExpression)
.Access.NoOp()
.Column("Id")
.Unique()
.Not.Insert()
.Not.Update()
.Cascade.All();
}
}
class PartAlteration<TPartRecord> : IAlteration<ContentItemRecord> where TPartRecord : ContentPartRecord {
public void Override(AutoMapping<ContentItemRecord> mapping) {
// public TPartRecord TPartRecord {get;set;}
var name = typeof(TPartRecord).Name;
var syntheticMethod = new DynamicMethod(name, typeof(TPartRecord), null, typeof(ContentItemRecord));
var syntheticProperty = new SyntheticPropertyInfo(syntheticMethod);
// record => record.TPartRecord
var parameter = Expression.Parameter(typeof(ContentItemRecord), "record");
var syntheticExpression = (Expression<Func<ContentItemRecord, TPartRecord>>)Expression.Lambda(
typeof(Func<ContentItemRecord, TPartRecord>),
Expression.Property(parameter, syntheticProperty),
parameter);
mapping.References(syntheticExpression)
.Access.NoOp()
.Column("Id")
.Unique()
.Not.Insert()
.Not.Update()
.Cascade.All();
}
}
class PartVersionAlteration<TPartRecord> : IAlteration<ContentItemVersionRecord> where TPartRecord : ContentPartVersionRecord {
public void Override(AutoMapping<ContentItemVersionRecord> mapping) {
// public TPartRecord TPartRecord {get;set;}
var name = typeof(TPartRecord).Name;
var syntheticMethod = new DynamicMethod(name, typeof(TPartRecord), null, typeof(ContentItemVersionRecord));
var syntheticProperty = new SyntheticPropertyInfo(syntheticMethod);
// record => record.TPartRecord
var parameter = Expression.Parameter(typeof(ContentItemVersionRecord), "record");
var syntheticExpression = (Expression<Func<ContentItemVersionRecord, TPartRecord>>)Expression.Lambda(
typeof(Func<ContentItemVersionRecord, TPartRecord>),
Expression.Property(parameter, syntheticProperty),
parameter);
mapping.References(syntheticExpression)
.Access.NoOp()
.Column("Id")
.Unique()
.Not.Insert()
.Not.Update()
.Cascade.All();
}
}
private class SyntheticPropertyInfo : PropertyInfo {
private readonly DynamicMethod _getMethod;
public SyntheticPropertyInfo(DynamicMethod dynamicMethod) {
_getMethod = dynamicMethod;
}
public override object[] GetCustomAttributes(bool inherit) {
throw new NotImplementedException();
}
public override bool IsDefined(Type attributeType, bool inherit) {
throw new NotImplementedException();
}
public override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture) {
throw new NotImplementedException();
}
public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture) {
throw new NotImplementedException();
}
public override MethodInfo[] GetAccessors(bool nonPublic) {
throw new NotImplementedException();
}
public override MethodInfo GetGetMethod(bool nonPublic) {
return _getMethod;
}
public override MethodInfo GetSetMethod(bool nonPublic) {
throw new NotImplementedException();
}
public override ParameterInfo[] GetIndexParameters() {
throw new NotImplementedException();
}
public override string Name {
get { return _getMethod.Name; }
}
public override Type DeclaringType {
get { throw new NotImplementedException(); }
}
public override Type ReflectedType {
get { throw new NotImplementedException(); }
}
public override Type PropertyType {
get { return _getMethod.ReturnType; }
}
public override PropertyAttributes Attributes {
get { throw new NotImplementedException(); }
}
public override bool CanRead {
get { return true; }
}
public override bool CanWrite {
get { throw new NotImplementedException(); }
}
public override object[] GetCustomAttributes(Type attributeType, bool inherit) {
throw new NotImplementedException();
}
}
}
}

View File

@@ -1,134 +0,0 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using System.Reflection.Emit;
using FluentNHibernate.Automapping;
using FluentNHibernate.Automapping.Alterations;
namespace Orchard.ContentManagement.Records {
class ContentItemRecordAlteration : IAutoMappingAlteration {
private readonly IEnumerable<Type> _recordTypes;
public ContentItemRecordAlteration() {
_recordTypes = Enumerable.Empty<Type>();
}
public ContentItemRecordAlteration(IEnumerable<Type> recordTypes) {
_recordTypes = recordTypes;
}
public void Alter(AutoPersistenceModel model) {
model.Override<ContentItemRecord>(mapping => {
foreach (var recordType in _recordTypes.Where(x => x.IsSubclassOf(typeof(ContentPartRecord)))) {
var type = typeof(Alteration<>).MakeGenericType(recordType);
var alteration = (IAlteration)Activator.CreateInstance(type);
alteration.Override(mapping);
}
});
}
interface IAlteration {
void Override(AutoMapping<ContentItemRecord> mapping);
}
class Alteration<TPartRecord> : IAlteration where TPartRecord : ContentPartRecord {
public void Override(AutoMapping<ContentItemRecord> mapping) {
// public TPartRecord TPartRecord {get;set;}
var name = typeof(TPartRecord).Name;
var syntheticMethod = new DynamicMethod(name, typeof(TPartRecord), null, typeof(ContentItemRecord));
var syntheticProperty = new SyntheticPropertyInfo(syntheticMethod);
// record => record.TPartRecord
var parameter = Expression.Parameter(typeof(ContentItemRecord), "record");
var syntheticExpression = (Expression<Func<ContentItemRecord, TPartRecord>>)Expression.Lambda(
typeof(Func<ContentItemRecord, TPartRecord>),
Expression.Property(parameter, syntheticProperty),
parameter);
mapping.References(syntheticExpression)
.Access.NoOp()
.Column("Id")
.Unique()
.Not.Insert()
.Not.Update()
.Cascade.All();
}
private class SyntheticPropertyInfo : PropertyInfo {
private readonly DynamicMethod _getMethod;
public SyntheticPropertyInfo(DynamicMethod dynamicMethod) {
_getMethod = dynamicMethod;
}
public override object[] GetCustomAttributes(bool inherit) {
throw new NotImplementedException();
}
public override bool IsDefined(Type attributeType, bool inherit) {
throw new NotImplementedException();
}
public override object GetValue(object obj, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture) {
throw new NotImplementedException();
}
public override void SetValue(object obj, object value, BindingFlags invokeAttr, Binder binder, object[] index, CultureInfo culture) {
throw new NotImplementedException();
}
public override MethodInfo[] GetAccessors(bool nonPublic) {
throw new NotImplementedException();
}
public override MethodInfo GetGetMethod(bool nonPublic) {
return _getMethod;
}
public override MethodInfo GetSetMethod(bool nonPublic) {
throw new NotImplementedException();
}
public override ParameterInfo[] GetIndexParameters() {
throw new NotImplementedException();
}
public override string Name {
get { return _getMethod.Name; }
}
public override Type DeclaringType {
get { throw new NotImplementedException(); }
}
public override Type ReflectedType {
get { throw new NotImplementedException(); }
}
public override Type PropertyType {
get { return _getMethod.ReturnType; }
}
public override PropertyAttributes Attributes {
get { throw new NotImplementedException(); }
}
public override bool CanRead {
get { return true; }
}
public override bool CanWrite {
get { throw new NotImplementedException(); }
}
public override object[] GetCustomAttributes(Type attributeType, bool inherit) {
throw new NotImplementedException();
}
}
}
}
}

View File

@@ -0,0 +1,55 @@
using System;
using System.Linq;
using FluentNHibernate.Automapping;
using FluentNHibernate.Automapping.Alterations;
namespace Orchard.ContentManagement.Records {
public class ContentPartAlteration : IAutoMappingAlteration {
public void Alter(AutoPersistenceModel model) {
model.OverrideAll(mapping => {
var recordType = mapping.GetType().GetGenericArguments().Single();
if (Utility.IsPartRecord(recordType)) {
var type = typeof(PartAlteration<>).MakeGenericType(recordType);
var alteration = (IAlteration)Activator.CreateInstance(type);
alteration.Override(mapping);
}
else if (Utility.IsPartVersionRecord(recordType)) {
var type = typeof(PartVersionAlteration<>).MakeGenericType(recordType);
var alteration = (IAlteration)Activator.CreateInstance(type);
alteration.Override(mapping);
}
});
}
interface IAlteration {
void Override(object mapping);
}
class PartAlteration<T> : IAlteration where T : ContentPartRecord {
public void Override(object mappingObj) {
var mapping = (AutoMapping<T>)mappingObj;
mapping.Id(x => x.Id)
.GeneratedBy.Foreign("ContentItemRecord");
mapping.HasOne(x => x.ContentItemRecord)
.Constrained();
}
}
class PartVersionAlteration<T> : IAlteration where T : ContentPartVersionRecord {
public void Override(object mappingObj) {
var mapping = (AutoMapping<T>)mappingObj;
mapping.Id(x => x.Id)
.GeneratedBy.Foreign("ContentItemVersionRecord");
mapping.HasOne(x => x.ContentItemVersionRecord)
.Constrained();
}
}
}
}

View File

@@ -1,39 +0,0 @@
using System;
using System.Linq;
using FluentNHibernate.Automapping;
using FluentNHibernate.Automapping.Alterations;
namespace Orchard.ContentManagement.Records {
public class ContentPartRecordAlteration : IAutoMappingAlteration {
public void Alter(AutoPersistenceModel model) {
model.OverrideAll(mapping => {
var genericArguments = mapping.GetType().GetGenericArguments();
if (!genericArguments.Single().IsSubclassOf(typeof(ContentPartRecord))) {
return;
}
var type = typeof(Alteration<>).MakeGenericType(genericArguments);
var alteration = (IAlteration)Activator.CreateInstance(type);
alteration.Override(mapping);
});
}
interface IAlteration {
void Override(object mapping);
}
class Alteration<T> : IAlteration where T : ContentPartRecord {
public void Override(object mappingObj) {
var mapping = (AutoMapping<T>)mappingObj;
mapping.Id(x => x.Id)
.GeneratedBy.Foreign("ContentItemRecord");
mapping.HasOne(x => x.ContentItemRecord)
.Constrained();
}
}
}
}

View File

@@ -1,7 +1,5 @@
namespace Orchard.ContentManagement.Records {
public abstract class ContentPartVersionRecord {
public virtual int Id { get; set; }
public virtual ContentItemRecord ContentItemRecord { get; set; }
public abstract class ContentPartVersionRecord : ContentPartRecord {
public virtual ContentItemVersionRecord ContentItemVersionRecord { get; set; }
}
}

View File

@@ -1,38 +0,0 @@
using System;
using System.Linq;
using FluentNHibernate.Automapping;
using FluentNHibernate.Automapping.Alterations;
namespace Orchard.ContentManagement.Records {
public class ContentPartVersionRecordAlteration : IAutoMappingAlteration {
public void Alter(AutoPersistenceModel model) {
model.OverrideAll(mapping => {
var genericArguments = mapping.GetType().GetGenericArguments();
if (!genericArguments.Single().IsSubclassOf(typeof(ContentPartVersionRecord))) {
return;
}
var type = typeof(Alteration<>).MakeGenericType(genericArguments);
var alteration = (IAlteration)Activator.CreateInstance(type);
alteration.Override(mapping);
});
}
interface IAlteration {
void Override(object mapping);
}
class Alteration<T> : IAlteration where T : ContentPartVersionRecord {
public void Override(object mappingObj) {
var mapping = (AutoMapping<T>)mappingObj;
mapping.Id(x => x.Id)
.GeneratedBy.Foreign("ContentItemVersionRecord");
mapping.HasOne(x => x.ContentItemVersionRecord)
.Constrained();
}
}
}
}

View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Orchard.ContentManagement.Records {
public static class Utility {
public static bool IsPartRecord(Type type) {
return type.IsSubclassOf(typeof(ContentPartRecord)) && !type.IsSubclassOf(typeof(ContentPartVersionRecord));
}
public static bool IsPartVersionRecord(Type type) {
return type.IsSubclassOf(typeof(ContentPartVersionRecord));
}
}
}

View File

@@ -57,7 +57,7 @@ namespace Orchard.Data {
alt.Add(new AutoMappingOverrideAlteration(recordAssembly));
}
alt.AddFromAssemblyOf<DataModule>();
alt.Add(new ContentItemRecordAlteration(recordTypes));
alt.Add(new ContentItemAlteration(recordTypes));
})
.Conventions.AddFromAssemblyOf<DataModule>();
}

View File

@@ -110,7 +110,8 @@ namespace Orchard.Data {
public virtual void Update(T entity) {
Logger.Debug("Update {0}", entity);
Session.Update(entity);
Session.Evict(entity);
Session.SaveOrUpdateCopy(entity);
}
public virtual void Delete(T entity) {
@@ -119,7 +120,7 @@ namespace Orchard.Data {
}
public virtual void Copy(T source, T target) {
Logger.Debug("Delete {0}", source, target);
Logger.Debug("Copy {0} {1}", source, target);
var metadata = Session.SessionFactory.GetClassMetadata(typeof (T));
var values = metadata.GetPropertyValues(source, EntityMode.Poco);
metadata.SetPropertyValues(target, values, EntityMode.Poco);

View File

@@ -170,13 +170,13 @@
<Compile Include="ContentManagement\Drivers\PartDriver.cs" />
<Compile Include="ContentManagement\IUpdateModel.cs" />
<Compile Include="ContentManagement\Records\ContentItemRecord.cs" />
<Compile Include="ContentManagement\Records\ContentItemRecordAlteration.cs" />
<Compile Include="ContentManagement\Records\ContentItemAlteration.cs" />
<Compile Include="ContentManagement\Records\ContentItemVersionRecord.cs" />
<Compile Include="ContentManagement\Records\ContentPartRecord.cs" />
<Compile Include="ContentManagement\Records\ContentPartRecordAlteration.cs" />
<Compile Include="ContentManagement\Records\ContentPartAlteration.cs" />
<Compile Include="ContentManagement\Records\ContentPartVersionRecord.cs" />
<Compile Include="ContentManagement\Records\ContentPartVersionRecordAlteration.cs" />
<Compile Include="ContentManagement\Records\ContentTypeRecord.cs" />
<Compile Include="ContentManagement\Records\Utility.cs" />
<Compile Include="ContentManagement\ViewModels\ItemDisplayModel.cs" />
<Compile Include="ContentManagement\ViewModels\ItemEditorModel.cs" />
<Compile Include="ContentManagement\ViewModels\TemplateViewModel.cs" />

View File

@@ -5,7 +5,7 @@ using System.Linq;
namespace Orchard.Utility {
public static class ReadOnlyCollectionExtensions {
public static IList<T> ToReadOnlyCollection<T>(this IEnumerable<T> enumerable) {
return new ReadOnlyCollection<T>(enumerable.ToArray());
return new ReadOnlyCollection<T>(enumerable.ToList());
}
}
}