diff --git a/src/Umbraco.Core/Events/EventExtensions.cs b/src/Umbraco.Core/Events/EventExtensions.cs
index b1ca0143ac..22067db7c1 100644
--- a/src/Umbraco.Core/Events/EventExtensions.cs
+++ b/src/Umbraco.Core/Events/EventExtensions.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
+using Umbraco.Core.Persistence.UnitOfWork;
namespace Umbraco.Core.Events
{
@@ -48,6 +49,35 @@ namespace Umbraco.Core.Events
return false;
}
+ ///
+ /// Hack: this is used to perform IsRaisedEventCancelled when a uow cannot be reused
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal static bool IsRaisedEventCancelled(
+ this TypedEventHandler eventHandler,
+ TArgs args,
+ TSender sender,
+ IScopeUnitOfWorkProvider uowProvider)
+ where TArgs : CancellableEventArgs
+ {
+ using(var uow = uowProvider.GetReadOnlyUnitOfWork())
+ {
+ if (uow.EventManager.SupportsEventCancellation)
+ {
+ uow.EventManager.TrackEvent(eventHandler, sender, args);
+ return args.Cancel;
+ }
+ return false;
+ }
+
+ }
+
///
/// Raises the event
///
@@ -85,6 +115,31 @@ namespace Umbraco.Core.Events
eventManager.TrackEvent(eventHandler, sender, args);
}
+ ///
+ /// Hack: this is used to perform IsRaisedEventCancelled when a uow cannot be reused
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ internal static void RaiseEvent(
+ this TypedEventHandler eventHandler,
+ TArgs args,
+ TSender sender,
+ IScopeUnitOfWorkProvider uowProvider)
+ where TArgs : EventArgs
+ {
+ //This UOW is a readonly one but needs to be committed otherwise
+ // it will rollback outer scopes
+ using (var uow = uowProvider.GetUnitOfWork())
+ {
+ uow.EventManager.TrackEvent(eventHandler, sender, args);
+ uow.Commit();
+ }
+ }
+
// moves the last handler that was added to an instance event, to first position
public static void PromoteLastHandler(object sender, string eventName)
{
diff --git a/src/Umbraco.Core/Persistence/UnitOfWork/ScopeUnitOfWorkProviderExtensions.cs b/src/Umbraco.Core/Persistence/UnitOfWork/ScopeUnitOfWorkProviderExtensions.cs
new file mode 100644
index 0000000000..1c0593ef7f
--- /dev/null
+++ b/src/Umbraco.Core/Persistence/UnitOfWork/ScopeUnitOfWorkProviderExtensions.cs
@@ -0,0 +1,18 @@
+namespace Umbraco.Core.Persistence.UnitOfWork
+{
+ internal static class ScopeUnitOfWorkProviderExtensions
+ {
+ ///
+ /// Hack: When we need a unit of work for readonly operations, the uow must be committed else the
+ /// outer scope will rollback, so this is a hack to create a unit of work, pre-commit it and return it
+ ///
+ ///
+ ///
+ public static IScopeUnitOfWork GetReadOnlyUnitOfWork(this IScopeUnitOfWorkProvider provider)
+ {
+ var uow = provider.GetUnitOfWork();
+ uow.Commit();
+ return uow;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs
index 25ea4da823..acfdce8291 100644
--- a/src/Umbraco.Core/Services/ContentService.cs
+++ b/src/Umbraco.Core/Services/ContentService.cs
@@ -66,7 +66,7 @@ namespace Umbraco.Core.Services
public int CountPublished(string contentTypeAlias = null)
{
- var uow = UowProvider.GetUnitOfWork();
+ var uow = UowProvider.GetReadOnlyUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
return repository.CountPublished();
@@ -75,7 +75,7 @@ namespace Umbraco.Core.Services
public int Count(string contentTypeAlias = null)
{
- var uow = UowProvider.GetUnitOfWork();
+ var uow = UowProvider.GetReadOnlyUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
return repository.Count(contentTypeAlias);
@@ -84,7 +84,7 @@ namespace Umbraco.Core.Services
public int CountChildren(int parentId, string contentTypeAlias = null)
{
- var uow = UowProvider.GetUnitOfWork();
+ var uow = UowProvider.GetReadOnlyUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
return repository.CountChildren(parentId, contentTypeAlias);
@@ -93,7 +93,7 @@ namespace Umbraco.Core.Services
public int CountDescendants(int parentId, string contentTypeAlias = null)
{
- var uow = UowProvider.GetUnitOfWork();
+ var uow = UowProvider.GetReadOnlyUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
return repository.CountDescendants(parentId, contentTypeAlias);
@@ -107,7 +107,7 @@ namespace Umbraco.Core.Services
///
public void ReplaceContentPermissions(EntityPermissionSet permissionSet)
{
- var uow = UowProvider.GetUnitOfWork();
+ var uow = UowProvider.GetReadOnlyUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
repository.ReplaceContentPermissions(permissionSet);
@@ -122,7 +122,7 @@ namespace Umbraco.Core.Services
///
public void AssignContentPermission(IContent entity, char permission, IEnumerable userIds)
{
- var uow = UowProvider.GetUnitOfWork();
+ var uow = UowProvider.GetReadOnlyUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
repository.AssignEntityPermission(entity, permission, userIds);
@@ -136,7 +136,7 @@ namespace Umbraco.Core.Services
///
public IEnumerable GetPermissionsForEntity(IContent content)
{
- var uow = UowProvider.GetUnitOfWork();
+ var uow = UowProvider.GetReadOnlyUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
return repository.GetPermissionsForEntity(content.Id);
@@ -164,18 +164,20 @@ namespace Umbraco.Core.Services
var parent = GetById(content.ParentId);
content.Path = string.Concat(parent.IfNotNull(x => x.Path, content.ParentId.ToString()), ",", content.Id);
- var uow = UowProvider.GetUnitOfWork();
-
- if (Creating.IsRaisedEventCancelled(new NewEventArgs(content, contentTypeAlias, parentId), this, uow.EventManager))
+ //we are using GetReadOnlyUnitOfWork because this actually doesn't write anything!
+ using (var uow = UowProvider.GetReadOnlyUnitOfWork())
{
- content.WasCancelled = true;
- return content;
+ if (Creating.IsRaisedEventCancelled(new NewEventArgs(content, contentTypeAlias, parentId), this, uow.EventManager))
+ {
+ content.WasCancelled = true;
+ return content;
+ }
+
+ content.CreatorId = userId;
+ content.WriterId = userId;
+
+ Created.RaiseEvent(new NewEventArgs(content, false, contentTypeAlias, parentId), this, uow.EventManager);
}
-
- content.CreatorId = userId;
- content.WriterId = userId;
-
- Created.RaiseEvent(new NewEventArgs(content, false, contentTypeAlias, parentId), this, uow.EventManager);
Audit(AuditType.New, string.Format("Content '{0}' was created", name), content.CreatorId, content.Id);
@@ -204,7 +206,8 @@ namespace Umbraco.Core.Services
var content = new Content(name, parent, contentType);
content.Path = string.Concat(parent.Path, ",", content.Id);
- using (var uow = UowProvider.GetUnitOfWork())
+ //we are using GetReadOnlyUnitOfWork because this actually doesn't write anything!
+ using (var uow = UowProvider.GetReadOnlyUnitOfWork())
{
if (Creating.IsRaisedEventCancelled(new NewEventArgs(content, contentTypeAlias, parent), this, uow.EventManager))
{
@@ -214,13 +217,13 @@ namespace Umbraco.Core.Services
content.CreatorId = userId;
content.WriterId = userId;
-
+
Created.RaiseEvent(new NewEventArgs(content, false, contentTypeAlias, parent), this, uow.EventManager);
-
- Audit(AuditType.New, string.Format("Content '{0}' was created", name), content.CreatorId, content.Id);
-
- return content;
}
+
+ Audit(AuditType.New, string.Format("Content '{0}' was created", name), content.CreatorId, content.Id);
+
+ return content;
}
///
@@ -240,23 +243,22 @@ namespace Umbraco.Core.Services
{
var contentType = FindContentTypeByAlias(contentTypeAlias);
var content = new Content(name, parentId, contentType);
-
- var uow = UowProvider.GetUnitOfWork();
-
+
//NOTE: I really hate the notion of these Creating/Created events - they are so inconsistent, I've only just found
// out that in these 'WithIdentity' methods, the Saving/Saved events were not fired, wtf. Anyways, they're added now.
- if (Creating.IsRaisedEventCancelled(new NewEventArgs(content, contentTypeAlias, parentId), this, uow.EventManager))
+ if (Creating.IsRaisedEventCancelled(new NewEventArgs(content, contentTypeAlias, parentId), this, UowProvider))
{
content.WasCancelled = true;
return content;
}
- if (Saving.IsRaisedEventCancelled(new SaveEventArgs(content), this, uow.EventManager))
+ if (Saving.IsRaisedEventCancelled(new SaveEventArgs(content), this, UowProvider))
{
content.WasCancelled = true;
return content;
}
-
+
+ var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
content.CreatorId = userId;
@@ -296,22 +298,21 @@ namespace Umbraco.Core.Services
var contentType = FindContentTypeByAlias(contentTypeAlias);
var content = new Content(name, parent, contentType);
- var uow = UowProvider.GetUnitOfWork();
-
//NOTE: I really hate the notion of these Creating/Created events - they are so inconsistent, I've only just found
// out that in these 'WithIdentity' methods, the Saving/Saved events were not fired, wtf. Anyways, they're added now.
- if (Creating.IsRaisedEventCancelled(new NewEventArgs(content, contentTypeAlias, parent), this, uow.EventManager))
+ if (Creating.IsRaisedEventCancelled(new NewEventArgs(content, contentTypeAlias, parent), this, UowProvider))
{
content.WasCancelled = true;
return content;
}
- if (Saving.IsRaisedEventCancelled(new SaveEventArgs(content), this, uow.EventManager))
+ if (Saving.IsRaisedEventCancelled(new SaveEventArgs(content), this, UowProvider))
{
content.WasCancelled = true;
return content;
}
-
+
+ var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
content.CreatorId = userId;
@@ -338,7 +339,7 @@ namespace Umbraco.Core.Services
///
public IContent GetById(int id)
{
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
return repository.Get(id);
}
@@ -354,7 +355,7 @@ namespace Umbraco.Core.Services
var idsArray = ids.ToArray();
if (idsArray.Length == 0) return Enumerable.Empty();
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
//ensure that the result has the order based on the ids passed in
var result = repository.GetAll(idsArray);
@@ -378,7 +379,7 @@ namespace Umbraco.Core.Services
///
public IContent GetById(Guid key)
{
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
var query = Query.Builder.Where(x => x.Key == key);
var contents = repository.GetByQuery(query);
@@ -393,7 +394,7 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
public IEnumerable GetContentOfContentType(int id)
{
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
var query = Query.Builder.Where(x => x.ContentTypeId == id);
var contents = repository.GetByQuery(query);
@@ -404,7 +405,7 @@ namespace Umbraco.Core.Services
internal IEnumerable GetPublishedContentOfContentType(int id)
{
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
var query = Query.Builder.Where(x => x.ContentTypeId == id);
var contents = repository.GetByPublishedVersion(query);
@@ -420,9 +421,9 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
public IEnumerable GetByLevel(int level)
{
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
- var query = Query.Builder.Where(x => x.Level == level && !x.Path.StartsWith(Constants.System.RecycleBinContent.ToInvariantString()));
+ var query = Query.Builder.Where(x => x.Level == level && x.Path.StartsWith(Constants.System.RecycleBinContent.ToInvariantString()) == false);
var contents = repository.GetByQuery(query);
return contents;
@@ -436,7 +437,7 @@ namespace Umbraco.Core.Services
/// An item
public IContent GetByVersion(Guid versionId)
{
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
return repository.GetByVersion(versionId);
}
@@ -450,7 +451,7 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
public IEnumerable GetVersions(int id)
{
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
var versions = repository.GetAllVersions(id);
return versions;
@@ -465,7 +466,7 @@ namespace Umbraco.Core.Services
///
public IEnumerable GetVersionIds(int id, int maxRows)
{
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
var versions = repository.GetVersionIds(id, maxRows);
return versions;
@@ -497,7 +498,7 @@ namespace Umbraco.Core.Services
if (ids.Any() == false)
return new List();
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
return repository.GetAll(ids);
}
@@ -510,7 +511,7 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
public IEnumerable GetChildren(int id)
{
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
var query = Query.Builder.Where(x => x.ParentId == id);
var contents = repository.GetByQuery(query).OrderBy(x => x.SortOrder);
@@ -564,7 +565,7 @@ namespace Umbraco.Core.Services
{
Mandate.ParameterCondition(pageIndex >= 0, "pageIndex");
Mandate.ParameterCondition(pageSize > 0, "pageSize");
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
var query = Query.Builder;
@@ -626,7 +627,7 @@ namespace Umbraco.Core.Services
{
Mandate.ParameterCondition(pageIndex >= 0, "pageIndex");
Mandate.ParameterCondition(pageSize > 0, "pageSize");
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
var query = Query.Builder;
@@ -663,7 +664,7 @@ namespace Umbraco.Core.Services
Mandate.ParameterCondition(pageIndex >= 0, "pageIndex");
Mandate.ParameterCondition(pageSize > 0, "pageSize");
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
var query = Query.Builder;
@@ -686,7 +687,7 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
public IEnumerable GetChildrenByName(int parentId, string name)
{
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
var query = Query.Builder.Where(x => x.ParentId == parentId && x.Name.Contains(name));
var contents = repository.GetByQuery(query);
@@ -721,7 +722,7 @@ namespace Umbraco.Core.Services
if (content.ValidatePath() == false)
throw new InvalidDataException(string.Format("The content item {0} has an invalid path: {1} with parentID: {2}", content.Id, content.Path, content.ParentId));
- var uow = UowProvider.GetUnitOfWork();
+ var uow = UowProvider.GetReadOnlyUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
var pathMatch = content.Path + ",";
@@ -786,7 +787,7 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
public IEnumerable GetRootContent()
{
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
var query = Query.Builder.Where(x => x.ParentId == Constants.System.Root);
var contents = repository.GetByQuery(query);
@@ -807,7 +808,7 @@ namespace Umbraco.Core.Services
_notTrashedQuery = Query.Builder.Where(x => x.Trashed == false);
}
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
return repository.GetByPublishedVersion(_notTrashedQuery);
}
@@ -819,7 +820,7 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
public IEnumerable GetContentForExpiration()
{
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
var query = Query.Builder.Where(x => x.Published == true && x.ExpireDate <= DateTime.Now);
var contents = repository.GetByQuery(query);
@@ -834,7 +835,7 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
public IEnumerable GetContentForRelease()
{
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
var query = Query.Builder.Where(x => x.Published == false && x.ReleaseDate <= DateTime.Now);
var contents = repository.GetByQuery(query);
@@ -849,7 +850,7 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
public IEnumerable GetContentInRecycleBin()
{
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
var query = Query.Builder.Where(x => x.Path.Contains(Constants.System.RecycleBinContent.ToInvariantString()));
var contents = repository.GetByQuery(query);
@@ -872,7 +873,7 @@ namespace Umbraco.Core.Services
internal int CountChildren(int id)
{
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
var query = Query.Builder.Where(x => x.ParentId == id);
var count = repository.Count(query);
@@ -887,7 +888,7 @@ namespace Umbraco.Core.Services
/// True if the content has any published version otherwise False
public bool HasPublishedVersion(int id)
{
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
var query = Query.Builder.Where(x => x.Published == true && x.Id == id && x.Trashed == false);
int count = repository.Count(query);
@@ -1000,70 +1001,17 @@ namespace Umbraco.Core.Services
/// Optional Id of the User deleting the Content
Attempt IContentServiceOperations.MoveToRecycleBin(IContent content, int userId)
{
- var evtMsgs = EventMessagesFactory.Get();
+ var evtMsgs = EventMessagesFactory.Get();
+ using (new WriteLock(Locker))
{
//Hack: this ensures that the entity's path is valid and if not it fixes/persists it
//see: http://issues.umbraco.org/issue/U4-9336
content.EnsureValidPath(Logger, entity => GetById(entity.ParentId), QuickUpdate);
var originalPath = content.Path;
if (Trashing.IsRaisedEventCancelled(
new MoveEventArgs(evtMsgs, new MoveEventInfo(content, originalPath, Constants.System.RecycleBinContent)),
this, UowProvider))
{
return OperationStatus.Cancelled(evtMsgs);
}
+ var moveInfo = new List>
{
new MoveEventInfo(content, originalPath, Constants.System.RecycleBinContent)
};
+ //Make sure that published content is unpublished before being moved to the Recycle Bin
if (HasPublishedVersion(content.Id))
{
//TODO: this shouldn't be a 'sub operation', and if it needs to be it cannot raise events and cannot be cancelled!
UnPublish(content, userId);
}
+ //Unpublish descendents of the content item that is being moved to trash
var descendants = GetDescendants(content).OrderBy(x => x.Level).ToList();
+ foreach (var descendant in descendants)
{
//TODO: this shouldn't be a 'sub operation', and if it needs to be it cannot raise events and cannot be cancelled!
+ UnPublish(descendant, userId);
}
+ var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
content.WriterId = userId;
content.ChangeTrashedState(true);
repository.AddOrUpdate(content);
+ //Loop through descendants to update their trash state, but ensuring structure by keeping the ParentId
foreach (var descendant in descendants)
{
moveInfo.Add(new MoveEventInfo(descendant, descendant.Path, descendant.ParentId));
descendant.WriterId = userId;
descendant.ChangeTrashedState(true, descendant.ParentId);
repository.AddOrUpdate(descendant);
}
uow.Commit();
- using (new WriteLock(Locker))
- {
- var uow = UowProvider.GetUnitOfWork();
-
- //Hack: this ensures that the entity's path is valid and if not it fixes/persists it
- //see: http://issues.umbraco.org/issue/U4-9336
- content.EnsureValidPath(Logger, entity => GetById(entity.ParentId), QuickUpdate);
-
- var originalPath = content.Path;
-
- if (Trashing.IsRaisedEventCancelled(
- new MoveEventArgs(evtMsgs, new MoveEventInfo(content, originalPath, Constants.System.RecycleBinContent)),
- this, uow.EventManager))
- {
- return OperationStatus.Cancelled(evtMsgs);
- }
-
- var moveInfo = new List>
- {
- new MoveEventInfo(content, originalPath, Constants.System.RecycleBinContent)
- };
-
- //Make sure that published content is unpublished before being moved to the Recycle Bin
- if (HasPublishedVersion(content.Id))
- {
- //TODO: this shouldn't be a 'sub operation', and if it needs to be it cannot raise events and cannot be cancelled!
- UnPublish(content, userId);
- }
-
- //Unpublish descendents of the content item that is being moved to trash
- var descendants = GetDescendants(content).OrderBy(x => x.Level).ToList();
- foreach (var descendant in descendants)
- {
- //TODO: this shouldn't be a 'sub operation', and if it needs to be it cannot raise events and cannot be cancelled!
- UnPublish(descendant, userId);
- }
-
- using (var repository = RepositoryFactory.CreateContentRepository(uow))
- {
- content.WriterId = userId;
- content.ChangeTrashedState(true);
- repository.AddOrUpdate(content);
-
- //Loop through descendants to update their trash state, but ensuring structure by keeping the ParentId
- foreach (var descendant in descendants)
- {
- moveInfo.Add(new MoveEventInfo(descendant, descendant.Path, descendant.ParentId));
-
- descendant.WriterId = userId;
- descendant.ChangeTrashedState(true, descendant.ParentId);
- repository.AddOrUpdate(descendant);
- }
-
- uow.Commit();
- }
-
- Trashed.RaiseEvent(new MoveEventArgs(false, evtMsgs, moveInfo.ToArray()), this, uow.EventManager);
-
- Audit(AuditType.Move, "Move Content to Recycle Bin performed by user", userId, content.Id);
-
- return OperationStatus.Success(evtMsgs);
- }
+ Trashed.RaiseEvent(new MoveEventArgs(false, evtMsgs, moveInfo.ToArray()), this, uow.EventManager);
}
Audit(AuditType.Move, "Move Content to Recycle Bin performed by user", userId, content.Id);
return OperationStatus.Success(evtMsgs);
}
}
///
@@ -1178,22 +1126,22 @@ namespace Umbraco.Core.Services
var asArray = contents.ToArray();
var evtMsgs = EventMessagesFactory.Get();
-
- var uow = UowProvider.GetUnitOfWork();
-
+
if (raiseEvents)
{
if (Saving.IsRaisedEventCancelled(
new SaveEventArgs(asArray, evtMsgs),
- this, uow.EventManager))
+ this, UowProvider))
{
return OperationStatus.Cancelled(evtMsgs);
}
}
+
using (new WriteLock(Locker))
{
var containsNew = asArray.Any(x => x.HasIdentity == false);
-
+
+ var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
if (containsNew)
@@ -1247,16 +1195,15 @@ namespace Umbraco.Core.Services
{
var evtMsgs = EventMessagesFactory.Get();
- using (new WriteLock(Locker))
- {
- var uow = UowProvider.GetUnitOfWork();
-
- if (Deleting.IsRaisedEventCancelled(
+ if (Deleting.IsRaisedEventCancelled(
new DeleteEventArgs(content, evtMsgs),
- this, uow.EventManager))
- {
- return OperationStatus.Cancelled(evtMsgs);
- }
+ this, UowProvider))
+ {
+ return OperationStatus.Cancelled(evtMsgs);
+ }
+
+ using (new WriteLock(Locker))
+ {
//Make sure that published content is unpublished before being deleted
if (HasPublishedVersion(content.Id))
@@ -1270,7 +1217,8 @@ namespace Umbraco.Core.Services
{
Delete(child, userId);
}
-
+
+ var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
repository.Delete(content);
@@ -1341,17 +1289,23 @@ namespace Umbraco.Core.Services
// The main problem with this is that for every content item being deleted, events are raised...
// which we need for many things like keeping caches in sync, but we can surely do this MUCH better.
+ var childList = new List();
+ var contentList = new List();
+
using (new WriteLock(Locker))
{
- using (var uow = UowProvider.GetUnitOfWork())
- {
- var repository = RepositoryFactory.CreateContentRepository(uow);
+ var uow = UowProvider.GetUnitOfWork();
+ using (var repository = RepositoryFactory.CreateContentRepository(uow))
+ {
//NOTE What about content that has the contenttype as part of its composition?
var query = Query.Builder.Where(x => x.ContentTypeId == contentTypeId);
var contents = repository.GetByQuery(query).ToArray();
if (Deleting.IsRaisedEventCancelled(new DeleteEventArgs(contents), this, uow.EventManager))
+ {
+ uow.Commit();
return;
+ }
foreach (var content in contents.OrderByDescending(x => x.ParentId))
{
@@ -1362,15 +1316,30 @@ namespace Umbraco.Core.Services
foreach (var child in children)
{
- if (child.ContentType.Id != contentTypeId)
- MoveToRecycleBin(child, userId);
+ //track children for moving to the bin
+ childList.Add(child);
}
- //Permantly delete the content
- Delete(content, userId);
+ //track content for deletion
+ contentList.Add(content);
}
}
+ //We need to do this outside of the uow because otherwise we'll have nested uow's
+ //TODO: this is a problem because we are doing all of this logic in the Service when it should
+ //all be happening in the repository
+
+ foreach (var child in childList)
+ {
+ if (child.ContentType.Id != contentTypeId)
+ MoveToRecycleBin(child, userId);
+ }
+ foreach (var content in contentList)
+ {
+ //Permantly delete the content
+ Delete(content, userId);
+ }
+
Audit(AuditType.Delete,
string.Format("Delete Content of Type {0} performed by user", contentTypeId),
userId, Constants.System.Root);
@@ -1401,17 +1370,17 @@ namespace Umbraco.Core.Services
public void DeleteVersions(int id, DateTime versionDate, int userId = 0)
{
var uow = UowProvider.GetUnitOfWork();
-
- if (DeletingVersions.IsRaisedEventCancelled(new DeleteRevisionsEventArgs(id, dateToRetain: versionDate), this, uow.EventManager))
- return;
-
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
+ if (DeletingVersions.IsRaisedEventCancelled(new DeleteRevisionsEventArgs(id, dateToRetain: versionDate), this, uow.EventManager))
+ {
+ uow.Commit();
+ return;
+ }
repository.DeleteVersions(id, versionDate);
uow.Commit();
- }
-
- DeletedVersions.RaiseEvent(new DeleteRevisionsEventArgs(id, false, dateToRetain: versionDate), this, uow.EventManager);
+ DeletedVersions.RaiseEvent(new DeleteRevisionsEventArgs(id, false, dateToRetain: versionDate), this, uow.EventManager);
+ }
Audit(AuditType.Delete, "Delete Content by version date performed by user", userId, Constants.System.Root);
}
@@ -1428,9 +1397,7 @@ namespace Umbraco.Core.Services
{
using (new WriteLock(Locker))
{
- var uow = UowProvider.GetUnitOfWork();
-
- if (DeletingVersions.IsRaisedEventCancelled(new DeleteRevisionsEventArgs(id, specificVersion: versionId), this, uow.EventManager))
+ if (DeletingVersions.IsRaisedEventCancelled(new DeleteRevisionsEventArgs(id, specificVersion: versionId), this, UowProvider))
return;
if (deletePriorVersions)
@@ -1438,15 +1405,15 @@ namespace Umbraco.Core.Services
var content = GetByVersion(versionId);
DeleteVersions(id, content.UpdateDate, userId);
}
-
+
+ var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
repository.DeleteVersion(versionId);
uow.Commit();
+ DeletedVersions.RaiseEvent(new DeleteRevisionsEventArgs(id, false, specificVersion: versionId), this, uow.EventManager);
}
- DeletedVersions.RaiseEvent(new DeleteRevisionsEventArgs(id, false, specificVersion: versionId), this, uow.EventManager);
-
Audit(AuditType.Delete, "Delete Content by version performed by user", userId, Constants.System.Root);
}
}
@@ -1475,32 +1442,29 @@ namespace Umbraco.Core.Services
/// Optional Id of the User moving the Content
public void Move(IContent content, int parentId, int userId = 0)
{
+ if (Moving.IsRaisedEventCancelled(
+ new MoveEventArgs(
+ new MoveEventInfo(content, content.Path, parentId)), this, UowProvider))
+ {
+ return;
+ }
+
+ //This ensures that the correct method is called if this method is used to Move to recycle bin.
+ if (parentId == Constants.System.RecycleBinContent)
+ {
+ MoveToRecycleBin(content, userId);
+ return;
+ }
+
using (new WriteLock(Locker))
{
- //This ensures that the correct method is called if this method is used to Move to recycle bin.
- if (parentId == Constants.System.RecycleBinContent)
- {
- MoveToRecycleBin(content, userId);
- return;
- }
+ //used to track all the moved entities to be given to the event
+ var moveInfo = new List>();
- using (var uow = UowProvider.GetUnitOfWork())
- {
- if (Moving.IsRaisedEventCancelled(
- new MoveEventArgs(
- new MoveEventInfo(content, content.Path, parentId)), this, uow.EventManager))
- {
- return;
- }
+ //call private method that does the recursive moving
+ PerformMove(content, parentId, userId, moveInfo);
- //used to track all the moved entities to be given to the event
- var moveInfo = new List>();
-
- //call private method that does the recursive moving
- PerformMove(content, parentId, userId, moveInfo);
-
- Moved.RaiseEvent(new MoveEventArgs(false, moveInfo.ToArray()), this, uow.EventManager);
- }
+ Moved.RaiseEvent(new MoveEventArgs(false, moveInfo.ToArray()), this, UowProvider);
Audit(AuditType.Move, "Move Content performed by user", userId, content.Id);
}
@@ -1530,14 +1494,17 @@ namespace Umbraco.Core.Services
files = ((ContentRepository)repository).GetFilesInRecycleBinForUploadField();
if (EmptyingRecycleBin.IsRaisedEventCancelled(new RecycleBinEventArgs(nodeObjectType, entities, files), this, uow.EventManager))
+ {
+ uow.Commit();
return;
+ }
success = repository.EmptyRecycleBin();
- EmptiedRecycleBin.RaiseEvent(new RecycleBinEventArgs(nodeObjectType, entities, files, success), this, uow.EventManager);
-
if (success)
repository.DeleteMediaFiles(files);
+
+ EmptiedRecycleBin.RaiseEvent(new RecycleBinEventArgs(nodeObjectType, entities, files, success), this, uow.EventManager);
}
}
Audit(AuditType.Delete, "Empty Content Recycle Bin performed by user", 0, Constants.System.RecycleBinContent);
@@ -1581,12 +1548,14 @@ namespace Umbraco.Core.Services
copy.ChangePublishedState(PublishedState.Unpublished);
var uow = UowProvider.GetUnitOfWork();
-
- if (Copying.IsRaisedEventCancelled(new CopyEventArgs(content, copy, parentId), this, uow.EventManager))
- return null;
-
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
+ if (Copying.IsRaisedEventCancelled(new CopyEventArgs(content, copy, parentId), this, uow.EventManager))
+ {
+ uow.Commit();
+ return null;
+ }
+
// Update the create author and last edit author
copy.CreatorId = userId;
copy.WriterId = userId;
@@ -1623,7 +1592,7 @@ namespace Umbraco.Core.Services
}
}
- Copied.RaiseEvent(new CopyEventArgs(content, copy, false, parentId, relateToOriginal), this, uow.EventManager);
+ Copied.RaiseEvent(new CopyEventArgs(content, copy, false, parentId, relateToOriginal), this, UowProvider);
Audit(AuditType.Copy, "Copy Content performed by user", content.WriterId, content.Id);
return copy;
@@ -1639,20 +1608,17 @@ namespace Umbraco.Core.Services
/// True if sending publication was succesfull otherwise false
public bool SendToPublication(IContent content, int userId = 0)
{
- using (var uow = UowProvider.GetUnitOfWork())
- {
- if (SendingToPublish.IsRaisedEventCancelled(new SendToPublishEventArgs(content), this, uow.EventManager))
- return false;
+ if (SendingToPublish.IsRaisedEventCancelled(new SendToPublishEventArgs(content), this, UowProvider))
+ return false;
- //Save before raising event
- Save(content, userId);
+ //Save before raising event
+ Save(content, userId);
- SentToPublish.RaiseEvent(new SendToPublishEventArgs(content, false), this, uow.EventManager);
+ SentToPublish.RaiseEvent(new SendToPublishEventArgs(content, false), this, UowProvider);
- Audit(AuditType.SendToPublish, "Send to Publish performed by user", content.WriterId, content.Id);
+ Audit(AuditType.SendToPublish, "Send to Publish performed by user", content.WriterId, content.Id);
- return true;
- }
+ return true;
}
///
@@ -1672,12 +1638,14 @@ namespace Umbraco.Core.Services
var content = GetByVersion(versionId);
var uow = UowProvider.GetUnitOfWork();
-
- if (RollingBack.IsRaisedEventCancelled(new RollbackEventArgs(content), this, uow.EventManager))
- return content;
-
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
+ if (RollingBack.IsRaisedEventCancelled(new RollbackEventArgs(content), this, uow.EventManager))
+ {
+ uow.Commit();
+ return content;
+ }
+
content.WriterId = userId;
content.CreatorId = userId;
content.ChangePublishedState(PublishedState.Unpublished);
@@ -1686,10 +1654,9 @@ namespace Umbraco.Core.Services
//add or update a preview
repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c));
uow.Commit();
+ RolledBack.RaiseEvent(new RollbackEventArgs(content, false), this, uow.EventManager);
}
- RolledBack.RaiseEvent(new RollbackEventArgs(content, false), this, uow.EventManager);
-
Audit(AuditType.RollBack, "Content rollback performed by user", content.WriterId, content.Id);
return content;
@@ -1715,16 +1682,18 @@ namespace Umbraco.Core.Services
using (new WriteLock(Locker))
{
var uow = UowProvider.GetUnitOfWork();
-
- var asArray = items.ToArray();
- if (raiseEvents)
- {
- if (Saving.IsRaisedEventCancelled(new SaveEventArgs(asArray), this, uow.EventManager))
- return false;
- }
-
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
+ var asArray = items.ToArray();
+ if (raiseEvents)
+ {
+ if (Saving.IsRaisedEventCancelled(new SaveEventArgs(asArray), this, uow.EventManager))
+ {
+ uow.Commit();
+ return false;
+ }
+ }
+
int i = 0;
foreach (var content in asArray)
{
@@ -1762,10 +1731,10 @@ namespace Umbraco.Core.Services
}
uow.Commit();
- }
- if (raiseEvents)
- Saved.RaiseEvent(new SaveEventArgs(asArray, false), this, uow.EventManager);
+ if (raiseEvents)
+ Saved.RaiseEvent(new SaveEventArgs(asArray, false), this, uow.EventManager);
+ }
if (shouldBePublished.Any())
{
@@ -1774,7 +1743,6 @@ namespace Umbraco.Core.Services
}
}
-
Audit(AuditType.Sort, "Sorting content performed by user", userId, 0);
return true;
@@ -1786,7 +1754,7 @@ namespace Umbraco.Core.Services
///
public XmlDocument BuildXmlCache()
{
- var uow = UowProvider.GetUnitOfWork();
+ var uow = UowProvider.GetReadOnlyUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
var result = repository.BuildXmlCache();
@@ -1803,7 +1771,7 @@ namespace Umbraco.Core.Services
///
public void RebuildXmlStructures(params int[] contentTypeIds)
{
- var uow = UowProvider.GetUnitOfWork();
+ var uow = UowProvider.GetReadOnlyUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
repository.RebuildXmlStructures(
@@ -1826,7 +1794,7 @@ namespace Umbraco.Core.Services
/// An Enumerable list of objects
internal IEnumerable GetPublishedDescendants(IContent content)
{
- using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
var query = Query.Builder.Where(x => x.Id != content.Id && x.Path.StartsWith(content.Path) && x.Trashed == false);
var contents = repository.GetByPublishedVersion(query);
@@ -2100,12 +2068,11 @@ namespace Umbraco.Core.Services
using (new WriteLock(Locker))
{
- var uow = UowProvider.GetUnitOfWork();
-
+
if (raiseEvents)
{
if (Saving.IsRaisedEventCancelled(
- new SaveEventArgs(content, evtMsgs), this, uow.EventManager))
+ new SaveEventArgs(content, evtMsgs), this, UowProvider))
{
return Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent, evtMsgs));
}
@@ -2137,7 +2104,8 @@ namespace Umbraco.Core.Services
//we are successfully published if our publishStatus is still Successful
bool published = publishStatus.StatusType == PublishStatusType.Success;
-
+
+ var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
if (published == false)
@@ -2163,10 +2131,10 @@ namespace Umbraco.Core.Services
}
uow.Commit();
- }
- if (raiseEvents)
- Saved.RaiseEvent(new SaveEventArgs(content, false, evtMsgs), this, uow.EventManager);
+ if (raiseEvents)
+ Saved.RaiseEvent(new SaveEventArgs(content, false, evtMsgs), this, uow.EventManager);
+ }
//Save xml to db and call following method to fire event through PublishingStrategy to update cache
if (published)
@@ -2201,18 +2169,17 @@ namespace Umbraco.Core.Services
using (new WriteLock(Locker))
{
- var uow = UowProvider.GetUnitOfWork();
-
if (raiseEvents)
{
if (Saving.IsRaisedEventCancelled(
new SaveEventArgs(content, evtMsgs),
- this, uow.EventManager))
+ this, UowProvider))
{
return OperationStatus.Cancelled(evtMsgs);
}
}
+ var uow = UowProvider.GetUnitOfWork();
using (var repository = RepositoryFactory.CreateContentRepository(uow))
{
if (content.HasIdentity == false)
@@ -2231,10 +2198,10 @@ namespace Umbraco.Core.Services
repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c));
uow.Commit();
- }
- if (raiseEvents)
- Saved.RaiseEvent(new SaveEventArgs(content, false, evtMsgs), this, uow.EventManager);
+ if (raiseEvents)
+ Saved.RaiseEvent(new SaveEventArgs(content, false, evtMsgs), this, uow.EventManager);
+ }
Audit(AuditType.Save, "Save Content performed by user", userId, content.Id);
@@ -2324,7 +2291,7 @@ namespace Umbraco.Core.Services
private IContentType FindContentTypeByAlias(string contentTypeAlias)
{
- using (var repository = RepositoryFactory.CreateContentTypeRepository(UowProvider.GetUnitOfWork()))
+ using (var repository = RepositoryFactory.CreateContentTypeRepository(UowProvider.GetReadOnlyUnitOfWork()))
{
var query = Query.Builder.Where(x => x.Alias == contentTypeAlias);
var types = repository.GetByQuery(query);
diff --git a/src/Umbraco.Core/Umbraco.Core.csproj b/src/Umbraco.Core/Umbraco.Core.csproj
index 17506e9a81..a5806da1cc 100644
--- a/src/Umbraco.Core/Umbraco.Core.csproj
+++ b/src/Umbraco.Core/Umbraco.Core.csproj
@@ -513,6 +513,7 @@
+