From 08c8b84a10c71c3a4a4ae91c274f257fa7454b12 Mon Sep 17 00:00:00 2001 From: Stephan Date: Fri, 17 Feb 2017 09:54:50 +0100 Subject: [PATCH] U4-9462 - cleanup units of work, code, fixmes --- src/Umbraco.Core/ApplicationContext.cs | 6 +- .../Cache/DefaultRepositoryCachePolicy.cs | 8 +- .../Cache/IRepositoryCachePolicy.cs | 11 +- src/Umbraco.Core/DatabaseContext.cs | 40 +- src/Umbraco.Core/Deploy/IFileSource.cs | 12 +- .../Events/ScopeEventDispatcher.cs | 18 +- .../IO/FileSystemProviderManager.cs | 3 +- src/Umbraco.Core/IO/MediaFileSystem.cs | 28 +- src/Umbraco.Core/IO/PhysicalFileSystem.cs | 8 +- src/Umbraco.Core/Models/ContentExtensions.cs | 25 +- .../Models/ContentTypeExtensions.cs | 85 ---- .../Repositories/PetaPocoRepositoryBase.cs | 7 +- .../Repositories/RepositoryBase.cs | 17 +- .../ServerRegistrationRepository.cs | 4 +- .../Persistence/UnitOfWork/FileUnitOfWork.cs | 20 - .../UnitOfWork/IScopeUnitOfWorkProvider.cs | 18 +- .../Persistence/UnitOfWork/ScopeUnitOfWork.cs | 23 +- .../UnitOfWork/ScopeUnitOfWorkProvider.cs | 32 +- src/Umbraco.Core/Scoping/ScopeProvider.cs | 1 + src/Umbraco.Core/Services/ContentService.cs | 390 ++++++++---------- .../Services/ContentTypeService.cs | 283 +++++++------ .../Services/ContentTypeServiceBase.cs | 20 +- src/Umbraco.Core/Services/DataTypeService.cs | 62 ++- src/Umbraco.Core/Services/DomainService.cs | 10 +- src/Umbraco.Core/Services/FileService.cs | 173 ++++---- .../Services/LocalizationService.cs | 85 ++-- src/Umbraco.Core/Services/MacroService.cs | 32 +- src/Umbraco.Core/Services/MediaService.cs | 295 ++++++------- .../Services/MemberGroupService.cs | 20 +- src/Umbraco.Core/Services/MemberService.cs | 109 +++-- .../Services/MemberTypeService.cs | 22 +- .../Services/PublicAccessService.cs | 4 +- src/Umbraco.Core/Services/RelationService.cs | 38 +- src/Umbraco.Core/Services/SectionService.cs | 6 +- src/Umbraco.Core/Services/ServiceContext.cs | 40 +- src/Umbraco.Core/Services/UserService.cs | 75 ++-- src/Umbraco.Core/Umbraco.Core.csproj | 2 - .../IO/FileSystemProviderManagerTests.cs | 29 +- src/Umbraco.Tests/Logging/ConsoleLogger.cs | 2 - .../Scoping/ScopedRepositoryTests.cs | 8 +- src/Umbraco.Tests/Scoping/ScopedXmlTests.cs | 77 +++- .../Services/ContentTypeServiceTests.cs | 8 +- .../TestHelpers/BaseDatabaseFactoryTest.cs | 7 +- .../Cache/CacheRefresherEventHandler.cs | 387 ++++++++--------- .../Cache/ContentTypeCacheRefresher.cs | 5 +- src/Umbraco.Web/Profiling/WebProfiler.cs | 20 +- .../FileUploadPropertyEditor.cs | 12 +- .../ImageCropperPropertyEditor.cs | 4 +- .../ImageCropperPropertyValueEditor.cs | 27 +- .../Scheduling/BackgroundTaskRunner.cs | 10 +- .../SafeXmlReaderWriter.cs | 53 +-- .../umbraco.presentation/content.cs | 83 ++-- 52 files changed, 1283 insertions(+), 1481 deletions(-) delete mode 100644 src/Umbraco.Core/Models/ContentTypeExtensions.cs delete mode 100644 src/Umbraco.Core/Persistence/UnitOfWork/FileUnitOfWork.cs diff --git a/src/Umbraco.Core/ApplicationContext.cs b/src/Umbraco.Core/ApplicationContext.cs index 5b2caf409f..384ff6e34c 100644 --- a/src/Umbraco.Core/ApplicationContext.cs +++ b/src/Umbraco.Core/ApplicationContext.cs @@ -1,8 +1,6 @@ using System; using System.Configuration; using System.Threading; -using System.Threading.Tasks; -using System.Web; using Umbraco.Core.Configuration; using Umbraco.Core.Logging; using Umbraco.Core.ObjectResolution; @@ -163,7 +161,9 @@ namespace Umbraco.Core /// public static ApplicationContext Current { get; internal set; } - // fixme + /// + /// Gets the scope provider. + /// internal IScopeProvider ScopeProvider { get { return _databaseContext == null ? null : _databaseContext.ScopeProvider; } } /// diff --git a/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs index fc98473c4c..57d12c4223 100644 --- a/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs +++ b/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs @@ -22,12 +22,12 @@ namespace Umbraco.Core.Cache { private static readonly TEntity[] EmptyEntities = new TEntity[0]; // const private readonly RepositoryCachePolicyOptions _options; - + public DefaultRepositoryCachePolicy(IRuntimeCacheProvider cache, RepositoryCachePolicyOptions options) : base(cache) - { + { if (options == null) throw new ArgumentNullException("options"); - _options = options; + _options = options; } public override IRepositoryCachePolicy Scoped(IRuntimeCacheProvider runtimeCache, IScope scope) @@ -244,9 +244,7 @@ namespace Umbraco.Core.Cache /// public override void ClearAll() { - // fixme the cache should NOT contain anything else so we can clean all, can't we? Cache.ClearAllCache(); - //Cache.ClearCacheByKeySearch(GetEntityTypeCacheKey()); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs index cd37ac1e60..eeb4f77de3 100644 --- a/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs +++ b/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs @@ -18,10 +18,17 @@ namespace Umbraco.Core.Cache // it is not *that* complicated but then RepositoryBase needs to have a TRepository generic // type parameter and it all becomes convoluted - keeping it simple for the time being. - // fixme explain + /// + /// Creates a scoped version of this cache policy. + /// + /// The global isolated runtime cache for this policy. + /// The scope. + /// When a policy is scoped, it means that it has been created with a scoped + /// isolated runtime cache, and now it needs to be wrapped into something that can apply + /// changes to the global isolated runtime cache. IRepositoryCachePolicy Scoped(IRuntimeCacheProvider runtimeCache, IScope scope); - /// + /// /// Gets an entity from the cache, else from the repository. /// /// The identifier. diff --git a/src/Umbraco.Core/DatabaseContext.cs b/src/Umbraco.Core/DatabaseContext.cs index 73780cae04..1409016da6 100644 --- a/src/Umbraco.Core/DatabaseContext.cs +++ b/src/Umbraco.Core/DatabaseContext.cs @@ -1,5 +1,4 @@ using System; -using System.Collections.Generic; using System.Configuration; using System.Data.SqlServerCe; using System.IO; @@ -34,7 +33,7 @@ namespace Umbraco.Core private string _connectionString; private string _providerName; private DatabaseSchemaResult _result; - private DateTime? _connectionLastChecked = null; + private DateTime? _connectionLastChecked; /// /// The number of minutes to throttle the checks to CanConnect @@ -99,10 +98,10 @@ namespace Umbraco.Core SqlSyntaxContext.SqlSyntaxProvider = SqlSyntax; var asDbFactory2 = factory as IDatabaseFactory2; - ScopeProvider = asDbFactory2 == null - ? new ScopeProvider(new DatabaseFactoryWrapper(factory)) + ScopeProvider = asDbFactory2 == null + ? new ScopeProvider(new DatabaseFactoryWrapper(factory)) : new ScopeProvider(asDbFactory2); - + _logger = logger; _configured = true; } @@ -197,42 +196,13 @@ namespace Umbraco.Core { throw new InvalidOperationException("Cannot create a database instance, there is no available connection string"); } - + return ScopeProvider.GetAmbientOrNoScope().Database; //var scope = ScopeProvider.AmbientScope; //return scope != null ? scope.Database : ScopeProvider.CreateNoScope().Database; } } - /// - /// Replaces the "ambient" database (if any) and by a new temp database. - /// - /// - /// The returned IDisposable *must* be diposed in order to properly dispose the temp database and - /// restore the original "ambient" database (if any). - /// This is to be used in background tasks to ensure that they have an "ambient" database which - /// will be properly removed from call context and does not interfere with anything else. In most case - /// it is not replacing anything, just temporarily installing a database in context. - /// - // fixme - this should just entirely be replaced by Scope? - /* - public virtual IDisposable UseSafeDatabase(bool force = false) - { - var factory = _factory as DefaultDatabaseFactory; - if (factory == null) throw new NotSupportedException(); - - if (DefaultDatabaseFactory.HasAmbientDatabase) - { - return force - ? new UsingDatabase(DefaultDatabaseFactory.DetachAmbientDatabase(), factory.CreateDatabase()) - : new UsingDatabase(null, null); - } - - // create a new, temp, database (will be disposed with UsingDatabase) - return new UsingDatabase(null, factory.CreateDatabase()); - } - */ - /// /// Boolean indicating whether the database has been configured /// diff --git a/src/Umbraco.Core/Deploy/IFileSource.cs b/src/Umbraco.Core/Deploy/IFileSource.cs index ea73d2b571..bc39841c3b 100644 --- a/src/Umbraco.Core/Deploy/IFileSource.cs +++ b/src/Umbraco.Core/Deploy/IFileSource.cs @@ -66,9 +66,19 @@ namespace Umbraco.Core.Deploy /// The length of the file, or -1 if the file does not exist. Task GetFileLengthAsync(StringUdi udi, CancellationToken token); - // fixme - doc + /// + /// Gets files and store them using a file store. + /// + /// The udis of the files to get. + /// A file store which can store the files. void GetFiles(IEnumerable udis, IFileStore fileStore); + /// + /// Gets files and store them using a file store. + /// + /// The udis of the files to get. + /// A file store which can store the files. + /// A cancellation token. Task GetFilesAsync(IEnumerable udis, IFileStore fileStore, CancellationToken token); ///// diff --git a/src/Umbraco.Core/Events/ScopeEventDispatcher.cs b/src/Umbraco.Core/Events/ScopeEventDispatcher.cs index 93315a9946..1cf6660a40 100644 --- a/src/Umbraco.Core/Events/ScopeEventDispatcher.cs +++ b/src/Umbraco.Core/Events/ScopeEventDispatcher.cs @@ -16,13 +16,17 @@ namespace Umbraco.Core.Events protected override void ScopeExitCompleted() { - // fixme - we'd need to de-duplicate events somehow, etc - and the deduplication should be last in wins + // processing only the last instance of each event... + // this is probably far from perfect, because if eg a content is saved in a list + // and then as a single content, the two events will probably not be de-duplicated, + // but it's better than nothing - foreach (var e in GetEvents(EventDefinitionFilter.All)) + foreach (var e in GetEvents(EventDefinitionFilter.LastIn)) { e.RaiseEvent(); - // fixme - not sure I like doing it here - but then where? how? + // separating concerns means that this should probably not be here, + // but then where should it be (without making things too complicated)? var delete = e.Args as IDeletingMediaFilesEventArgs; if (delete != null && delete.MediaFilesToDelete.Count > 0) MediaFileSystem.DeleteMediaFiles(delete.MediaFilesToDelete); @@ -35,13 +39,7 @@ namespace Umbraco.Core.Events { get { - if (_mediaFileSystem != null) return _mediaFileSystem; - - // fixme - insane! reading config goes cross AppDomain and serializes context? - using (new SafeCallContext()) - { - return _mediaFileSystem = FileSystemProviderManager.Current.MediaFileSystem; - } + return _mediaFileSystem ?? (_mediaFileSystem = FileSystemProviderManager.Current.MediaFileSystem); } } } diff --git a/src/Umbraco.Core/IO/FileSystemProviderManager.cs b/src/Umbraco.Core/IO/FileSystemProviderManager.cs index 5f0e014012..e593446c43 100644 --- a/src/Umbraco.Core/IO/FileSystemProviderManager.cs +++ b/src/Umbraco.Core/IO/FileSystemProviderManager.cs @@ -43,7 +43,8 @@ namespace Umbraco.Core.IO private IScopeProviderInternal ScopeProvider { - // fixme - 'course this is bad, but enough for now + // this is bad, but enough for now, and we'll refactor + // in v8 when we'll get rid of this class' singleton get { return ApplicationContext.Current == null ? null : ApplicationContext.Current.ScopeProvider as IScopeProviderInternal; } } diff --git a/src/Umbraco.Core/IO/MediaFileSystem.cs b/src/Umbraco.Core/IO/MediaFileSystem.cs index d9281a7590..bcb2ff8bfd 100644 --- a/src/Umbraco.Core/IO/MediaFileSystem.cs +++ b/src/Umbraco.Core/IO/MediaFileSystem.cs @@ -302,7 +302,7 @@ namespace Umbraco.Core.IO { var property = GetProperty(content, propertyTypeAlias); var svalue = property.Value as string; - var oldpath = svalue == null ? null : GetRelativePath(svalue); // FIXME DELETE? + var oldpath = svalue == null ? null : GetRelativePath(svalue); if (string.IsNullOrWhiteSpace(oldpath) == false && oldpath != filepath) DeleteFile(oldpath, true); property.Value = GetUrl(filepath); @@ -466,27 +466,6 @@ namespace Umbraco.Core.IO var dir = Path.GetDirectoryName(file); DeleteDirectory(dir, true); } - - // I don't even understand... - /* - - var relativeFilePath = GetRelativePath(file); // fixme - should be relative already - if (FileExists(relativeFilePath) == false) return; - - var parentDirectory = Path.GetDirectoryName(relativeFilePath); - - // don't want to delete the media folder if not using directories. - if (_contentSection.UploadAllowDirectories && parentDirectory != GetRelativePath("/")) - { - //issue U4-771: if there is a parent directory the recursive parameter should be true - DeleteDirectory(parentDirectory, string.IsNullOrEmpty(parentDirectory) == false); - } - else - { - DeleteFile(file, true); - } - - */ } catch (Exception e) { @@ -549,7 +528,7 @@ namespace Umbraco.Core.IO PropertyType propertyType) { // get the original image from the original stream - if (filestream.CanSeek) filestream.Seek(0, 0); // fixme - what if we cannot seek? + if (filestream.CanSeek) filestream.Seek(0, 0); using (var image = Image.FromStream(filestream)) { return GenerateThumbnails(image, filepath, propertyType); @@ -658,9 +637,6 @@ namespace Umbraco.Core.IO var rect = new Rectangle(0, 0, width, height); graphics.DrawImage(originImage, rect, 0, 0, originImage.Width, originImage.Height, GraphicsUnit.Pixel); - // copy metadata - // fixme - er... no? - // get an encoder - based upon the file type var extension = (Path.GetExtension(resizedFilepath) ?? "").TrimStart('.').ToLowerInvariant(); var encoders = ImageCodecInfo.GetImageEncoders(); diff --git a/src/Umbraco.Core/IO/PhysicalFileSystem.cs b/src/Umbraco.Core/IO/PhysicalFileSystem.cs index bf18d02e54..77c557cbfe 100644 --- a/src/Umbraco.Core/IO/PhysicalFileSystem.cs +++ b/src/Umbraco.Core/IO/PhysicalFileSystem.cs @@ -155,7 +155,9 @@ namespace Umbraco.Core.IO if (directory == null) throw new InvalidOperationException("Could not get directory."); Directory.CreateDirectory(directory); // ensure it exists - if (stream.CanSeek) // fixme - what else? + // if can seek, be safe and go back to start, else... + // hope that the stream hasn't been read already + if (stream.CanSeek) stream.Seek(0, 0); using (var destination = (Stream) File.Create(fullPath)) @@ -286,7 +288,9 @@ namespace Umbraco.Core.IO var opath = path; path = EnsureDirectorySeparatorChar(path); - // fixme - this part should go! + // TODO in v8 this should be cleaned up + // the first part should probably removed + // not sure what we are doing here - so if input starts with a (back) slash, // we assume it's not a FS relative path and we try to convert it... but it // really makes little sense? diff --git a/src/Umbraco.Core/Models/ContentExtensions.cs b/src/Umbraco.Core/Models/ContentExtensions.cs index 8423006f4d..c7e6829983 100644 --- a/src/Umbraco.Core/Models/ContentExtensions.cs +++ b/src/Umbraco.Core/Models/ContentExtensions.cs @@ -7,7 +7,6 @@ using System.Xml.Linq; using Newtonsoft.Json; using Newtonsoft.Json.Linq; using Umbraco.Core.IO; -using Umbraco.Core.Media; using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Models.Membership; using Umbraco.Core.Services; @@ -42,7 +41,7 @@ namespace Umbraco.Core.Models /// * The item exists and is published /// * A call to ContentService.Save is made /// * The item has not been modified whatsoever apart from changing it's published status from published to saved - /// + /// /// In this case, there is no reason to make any database changes at all /// internal static bool RequiresSaving(this IContent entity) @@ -62,7 +61,7 @@ namespace Umbraco.Core.Models /// * The item exists and is published /// * A call to ContentService.Save is made /// * The item has not been modified whatsoever apart from changing it's published status from published to saved - /// + /// /// In this case, there is no reason to make any database changes at all /// internal static bool RequiresSaving(this IContent entity, PublishedState publishedState) @@ -70,7 +69,7 @@ namespace Umbraco.Core.Models var publishedChanged = entity.IsPropertyDirty("Published") && publishedState != PublishedState.Unpublished; //check if any user prop has changed var propertyValueChanged = entity.IsAnyUserPropertyDirty(); - + //We need to know if any other property apart from Published was changed here //don't create a new version if the published state has changed to 'Save' but no data has actually been changed if (publishedChanged && entity.Published == false && propertyValueChanged == false) @@ -302,9 +301,9 @@ namespace Umbraco.Core.Models return content.Path.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries) .Contains(recycleBinId.ToInvariantString()); } - + /// - /// Removes characters that are not valide XML characters from all entity properties + /// Removes characters that are not valide XML characters from all entity properties /// of type string. See: http://stackoverflow.com/a/961504/5018 /// /// @@ -456,7 +455,7 @@ namespace Umbraco.Core.Models /// The uploaded . public static void SetValue(this IContentBase content, string propertyTypeAlias, HttpPostedFileBase value) { - // ensure we get the filename without the path in IE in intranet mode + // ensure we get the filename without the path in IE in intranet mode // http://stackoverflow.com/questions/382464/httppostedfile-filename-different-from-ie var filename = value.FileName; var pos = filename.LastIndexOf(@"\", StringComparison.InvariantCulture); @@ -468,10 +467,10 @@ namespace Umbraco.Core.Models if (pos > 0) filename = filename.Substring(pos + 1); - // get a safe filename - should this be done by MediaHelper? + // get a safe & clean filename filename = IOHelper.SafeFileName(filename); if (string.IsNullOrWhiteSpace(filename)) return; - filename = filename.ToLower(); // fixme - er... why? + filename = filename.ToLower(); FileSystemProviderManager.Current.MediaFileSystem.SetUploadFile(content, propertyTypeAlias, filename, value.InputStream); } @@ -513,10 +512,10 @@ namespace Umbraco.Core.Models { if (filename == null || filestream == null) return; - // get a safe filename - should this be done by MediaHelper? + // get a safe & clean filename filename = IOHelper.SafeFileName(filename); if (string.IsNullOrWhiteSpace(filename)) return; - filename = filename.ToLower(); // fixme - er... why? + filename = filename.ToLower(); FileSystemProviderManager.Current.MediaFileSystem.SetUploadFile(content, propertyTypeAlias, filename, filestream); } @@ -548,7 +547,7 @@ namespace Umbraco.Core.Models #endregion #region User/Profile methods - + /// /// Gets the for the Creator of this media item. /// @@ -623,7 +622,7 @@ namespace Umbraco.Core.Models ///// ///// ///// - ///// The tags returned are only relavent for published content & saved media or members + ///// The tags returned are only relavent for published content & saved media or members ///// //public static IEnumerable GetTags(this IContentBase content, string propertyTypeAlias, string tagGroup = "default") //{ diff --git a/src/Umbraco.Core/Models/ContentTypeExtensions.cs b/src/Umbraco.Core/Models/ContentTypeExtensions.cs deleted file mode 100644 index 90488219fc..0000000000 --- a/src/Umbraco.Core/Models/ContentTypeExtensions.cs +++ /dev/null @@ -1,85 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using Umbraco.Core.Services; - -namespace Umbraco.Core.Models -{ - //fixme: This whole thing needs to go, it's super hacky and doens't need to exist in the first place - internal static class ContentTypeExtensions - { - /// - /// Get all descendant content types - /// - /// - /// - /// - public static IEnumerable Descendants(this IContentTypeBase contentType, IContentTypeService contentTypeService) - { - if (contentType is IContentType) - { - var descendants = contentTypeService.GetContentTypeChildren(contentType.Id) - .SelectRecursive(type => contentTypeService.GetContentTypeChildren(type.Id)); - return descendants; - } - - if (contentType is IMediaType) - { - var descendants = contentTypeService.GetMediaTypeChildren(contentType.Id) - .SelectRecursive(type => contentTypeService.GetMediaTypeChildren(type.Id)); - return descendants; - } - - //No other content types have children (i.e. member types) - return Enumerable.Empty(); - } - - /// - /// Get all descendant content types - /// - /// - /// - /// - public static IEnumerable Descendants(this IContentTypeBase contentType, ContentTypeServiceBase contentTypeService) - { - var cService = contentTypeService as IContentTypeService; - - return cService == null ? Enumerable.Empty() : contentType.Descendants(cService); - } - - /// - /// Get all descendant and self content types - /// - /// - /// - /// - public static IEnumerable DescendantsAndSelf(this IContentTypeBase contentType, IContentTypeService contentTypeService) - { - var descendantsAndSelf = new[] { contentType }.Concat(contentType.Descendants(contentTypeService)); - return descendantsAndSelf; - } - - /// - /// Get all descendant and self content types - /// - /// - /// - /// - public static IEnumerable DescendantsAndSelf(this IContentTypeBase contentType, ContentTypeServiceBase contentTypeService) - { - var descendantsAndSelf = new[] { contentType }.Concat(contentType.Descendants(contentTypeService)); - return descendantsAndSelf; - } - - ///// - ///// Returns the descendant content type Ids for the given content type - ///// - ///// - ///// - //public static IEnumerable DescendantIds(this IContentTypeBase contentType) - //{ - // return ((ContentTypeService) ApplicationContext.Current.Services.ContentTypeService) - // .GetDescendantContentTypeIds(contentType.Id); - //} - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/PetaPocoRepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/PetaPocoRepositoryBase.cs index 2a34aeb153..dc61da119e 100644 --- a/src/Umbraco.Core/Persistence/Repositories/PetaPocoRepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/PetaPocoRepositoryBase.cs @@ -31,7 +31,7 @@ namespace Umbraco.Core.Persistence.Repositories /// protected internal new IScopeUnitOfWork UnitOfWork { - get { return (IScopeUnitOfWork)base.UnitOfWork; } + get { return base.UnitOfWork; } } protected UmbracoDatabase Database @@ -75,10 +75,5 @@ namespace Umbraco.Core.Persistence.Repositories Database.Execute(delete, new { Id = GetEntityId(entity) }); } } - - protected virtual TId GetEntityId(TEntity entity) - { - return (TId)(object)entity.Id; - } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs index 9061be62e4..91f8173304 100644 --- a/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs +++ b/src/Umbraco.Core/Persistence/Repositories/RepositoryBase.cs @@ -13,10 +13,10 @@ namespace Umbraco.Core.Persistence.Repositories { internal abstract class RepositoryBase : DisposableObject { - private readonly IUnitOfWork _work; + private readonly IScopeUnitOfWork _work; private readonly CacheHelper _globalCache; - protected RepositoryBase(IUnitOfWork work, CacheHelper cache, ILogger logger) + protected RepositoryBase(IScopeUnitOfWork work, CacheHelper cache, ILogger logger) { if (work == null) throw new ArgumentNullException("work"); if (cache == null) throw new ArgumentNullException("cache"); @@ -29,7 +29,7 @@ namespace Umbraco.Core.Persistence.Repositories /// /// Returns the Unit of Work added to the repository /// - protected internal IUnitOfWork UnitOfWork + protected internal IScopeUnitOfWork UnitOfWork { get { return _work; } } @@ -76,7 +76,7 @@ namespace Umbraco.Core.Persistence.Repositories internal abstract class RepositoryBase : RepositoryBase, IRepositoryQueryable, IUnitOfWorkRepository where TEntity : class, IAggregateRoot { - protected RepositoryBase(IUnitOfWork work, CacheHelper cache, ILogger logger) + protected RepositoryBase(IScopeUnitOfWork work, CacheHelper cache, ILogger logger) : base(work, cache, logger) { } @@ -102,7 +102,7 @@ namespace Umbraco.Core.Persistence.Repositories { if (_isolatedCache != null) return _isolatedCache; - var scope = ((ScopeUnitOfWork) UnitOfWork).Scope; // fixme cast! + var scope = UnitOfWork.Scope; IsolatedRuntimeCache provider; switch (scope.RepositoryCacheMode) { @@ -179,14 +179,17 @@ namespace Umbraco.Core.Persistence.Repositories if (GlobalCache == CacheHelper.NoCache) return _cachePolicy = NoRepositoryCachePolicy.Instance; + // create the cache policy using IsolatedCache which is either global + // or scoped depending on the repository cache mode for the current scope _cachePolicy = CreateCachePolicy(IsolatedCache); - var scope = ((ScopeUnitOfWork) UnitOfWork).Scope; // fixme cast! + var scope = UnitOfWork.Scope; switch (scope.RepositoryCacheMode) { case RepositoryCacheMode.Default: break; case RepositoryCacheMode.Scoped: - _cachePolicy = _cachePolicy.Scoped(GetIsolatedCache(GlobalCache.IsolatedRuntimeCache), scope); + var globalIsolatedCache = GetIsolatedCache(GlobalCache.IsolatedRuntimeCache); + _cachePolicy = _cachePolicy.Scoped(globalIsolatedCache, scope); break; default: throw new Exception("oops: cache mode."); diff --git a/src/Umbraco.Core/Persistence/Repositories/ServerRegistrationRepository.cs b/src/Umbraco.Core/Persistence/Repositories/ServerRegistrationRepository.cs index e3fad1aaf7..9cd47ded97 100644 --- a/src/Umbraco.Core/Persistence/Repositories/ServerRegistrationRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/ServerRegistrationRepository.cs @@ -21,7 +21,9 @@ namespace Umbraco.Core.Persistence.Repositories : base(work, CacheHelper.NoCache, logger, sqlSyntax) { // managing the cache our own way (no policy etc) - // fixme - ServerRegistrationRepository does *not* implement scoped cache at the moment! + // note: this means that the ServerRegistrationRepository does *not* implement scoped cache, + // and this is because the repository is special and should not participate in scopes + // (cleanup in v8) _globalCache = globalCache; } diff --git a/src/Umbraco.Core/Persistence/UnitOfWork/FileUnitOfWork.cs b/src/Umbraco.Core/Persistence/UnitOfWork/FileUnitOfWork.cs deleted file mode 100644 index b7f09999bb..0000000000 --- a/src/Umbraco.Core/Persistence/UnitOfWork/FileUnitOfWork.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Data; -using System.Linq; -using Umbraco.Core.Models.EntityBase; -using Umbraco.Core.Scoping; - -namespace Umbraco.Core.Persistence.UnitOfWork -{ - internal class FileUnitOfWork : ScopeUnitOfWork - { - // fixme - // soon as FileUnitOfWork inherits from ScopeUnitOfWork it does not make any sense anymore to keep this class around?! - - - public FileUnitOfWork(IScopeProvider scopeProvider, IsolationLevel isolationLevel = IsolationLevel.Unspecified) - : base(scopeProvider, isolationLevel) - { } - } -} \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/UnitOfWork/IScopeUnitOfWorkProvider.cs b/src/Umbraco.Core/Persistence/UnitOfWork/IScopeUnitOfWorkProvider.cs index ffab842909..89c8a8bb36 100644 --- a/src/Umbraco.Core/Persistence/UnitOfWork/IScopeUnitOfWorkProvider.cs +++ b/src/Umbraco.Core/Persistence/UnitOfWork/IScopeUnitOfWorkProvider.cs @@ -18,19 +18,9 @@ namespace Umbraco.Core.Persistence.UnitOfWork // creates a unit of work // support specifying an isolation level - // support auto-commit - beware! - // fixme - should we be able to specify ALL scope options? - // fixme - that isolation level thing is a pain because of the above existing method - IScopeUnitOfWork GetUnitOfWork(bool commit); - IScopeUnitOfWork GetUnitOfWork(IsolationLevel isolationLevel, bool commit = false); - - // creates a readonly unit of work - // the readonly unit of work will not accept operations, and will auto-complete - // of course it would be a bad idea to use it for anything else than reading - // fixme - implement that one FOR REAL not as an extension method - // the extension method was a ugly hack - // or maybe we want a autocommit flag in the ctor? - //IScopeUnitOfWork GetReadOnlyUnitOfWork(); - //IScopeUnitOfWork GetReadOnlyUnitOfWork(bool autocommit = false); + // support auto-commit - but beware! it will be committed, whatever happens + // TODO in v8 this should all be merged as one single method with optional args + IScopeUnitOfWork GetUnitOfWork(bool readOnly); + IScopeUnitOfWork GetUnitOfWork(IsolationLevel isolationLevel, bool readOnly = false); } } \ No newline at end of file diff --git a/src/Umbraco.Core/Persistence/UnitOfWork/ScopeUnitOfWork.cs b/src/Umbraco.Core/Persistence/UnitOfWork/ScopeUnitOfWork.cs index 1e6ae7f5b4..204e7b0bfe 100644 --- a/src/Umbraco.Core/Persistence/UnitOfWork/ScopeUnitOfWork.cs +++ b/src/Umbraco.Core/Persistence/UnitOfWork/ScopeUnitOfWork.cs @@ -16,6 +16,7 @@ namespace Umbraco.Core.Persistence.UnitOfWork private readonly IsolationLevel _isolationLevel; private readonly IScopeProvider _scopeProvider; private bool _completeScope; + private readonly bool _readOnly; private IScope _scope; private Guid _key; @@ -29,11 +30,11 @@ namespace Umbraco.Core.Persistence.UnitOfWork /// /// /// - /// + /// /// /// This should normally not be used directly and should be created with the UnitOfWorkProvider /// - internal ScopeUnitOfWork(IScopeProvider scopeProvider, IsolationLevel isolationLevel = IsolationLevel.Unspecified, bool commit = false) + internal ScopeUnitOfWork(IScopeProvider scopeProvider, IsolationLevel isolationLevel = IsolationLevel.Unspecified, bool readOnly = false) { _scopeProvider = scopeProvider; _isolationLevel = isolationLevel; @@ -43,7 +44,7 @@ namespace Umbraco.Core.Persistence.UnitOfWork // be false by default // if set to true... the UnitOfWork is "auto-commit" which means that even in the case of // an exception, the scope would still be completed - ppl should use it with great care! - _completeScope = commit; + _completeScope = _readOnly = readOnly; } /// @@ -53,6 +54,9 @@ namespace Umbraco.Core.Persistence.UnitOfWork /// The participating in the transaction public void RegisterAdded(IEntity entity, IUnitOfWorkRepository repository) { + if (_readOnly) + throw new NotSupportedException("This unit of work is read-only."); + _operations.Enqueue(new Operation { Entity = entity, @@ -68,7 +72,10 @@ namespace Umbraco.Core.Persistence.UnitOfWork /// The participating in the transaction public void RegisterChanged(IEntity entity, IUnitOfWorkRepository repository) { - _operations.Enqueue( + if (_readOnly) + throw new NotSupportedException("This unit of work is read-only."); + + _operations.Enqueue( new Operation { Entity = entity, @@ -84,7 +91,10 @@ namespace Umbraco.Core.Persistence.UnitOfWork /// The participating in the transaction public void RegisterRemoved(IEntity entity, IUnitOfWorkRepository repository) { - _operations.Enqueue( + if (_readOnly) + throw new NotSupportedException("This unit of work is read-only."); + + _operations.Enqueue( new Operation { Entity = entity, @@ -116,6 +126,9 @@ namespace Umbraco.Core.Persistence.UnitOfWork { // this happens in a scope-managed transaction + if (_readOnly) + throw new NotSupportedException("This unit of work is read-only."); + // in case anything goes wrong _completeScope = false; diff --git a/src/Umbraco.Core/Persistence/UnitOfWork/ScopeUnitOfWorkProvider.cs b/src/Umbraco.Core/Persistence/UnitOfWork/ScopeUnitOfWorkProvider.cs index 2e5950e3b2..9800b2bc55 100644 --- a/src/Umbraco.Core/Persistence/UnitOfWork/ScopeUnitOfWorkProvider.cs +++ b/src/Umbraco.Core/Persistence/UnitOfWork/ScopeUnitOfWorkProvider.cs @@ -24,48 +24,28 @@ namespace Umbraco.Core.Persistence.UnitOfWork return new ScopeUnitOfWork(ScopeProvider); } - /// - /// Creates a Unit of work with a new UmbracoDatabase instance for the work item/transaction. - /// - /// - /// - /// Each PetaPoco UOW uses it's own Database object, not the shared Database object that comes from - /// the ApplicationContext.Current.DatabaseContext.Database. This is because each transaction should use it's own Database - /// and we Dispose of this Database object when the UOW is disposed. - /// fixme NO we dispose of it when the transaction completes - /// fixme just inheritdoc! - /// + /// public virtual IScopeUnitOfWork GetUnitOfWork() { return new ScopeUnitOfWork(ScopeProvider); } - /// - /// Creates a Unit of work with a new UmbracoDatabase instance for the work item/transaction. - /// - /// - /// - /// Each PetaPoco UOW uses it's own Database object, not the shared Database object that comes from - /// the ApplicationContext.Current.DatabaseContext.Database. This is because each transaction should use it's own Database - /// and we Dispose of this Database object when the UOW is disposed. - /// fixme NO - /// fixme just inheritdoc! - /// + /// public IScopeUnitOfWork GetUnitOfWork(IsolationLevel isolationLevel) { return new ScopeUnitOfWork(ScopeProvider, isolationLevel); } /// - public IScopeUnitOfWork GetUnitOfWork(bool commit) + public IScopeUnitOfWork GetUnitOfWork(bool readOnly) { - return new ScopeUnitOfWork(ScopeProvider, commit: commit); + return new ScopeUnitOfWork(ScopeProvider, readOnly: readOnly); } /// - public IScopeUnitOfWork GetUnitOfWork(IsolationLevel isolationLevel, bool commit) + public IScopeUnitOfWork GetUnitOfWork(IsolationLevel isolationLevel, bool readOnly) { - return new ScopeUnitOfWork(ScopeProvider, isolationLevel, commit: commit); + return new ScopeUnitOfWork(ScopeProvider, isolationLevel, readOnly: readOnly); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Scoping/ScopeProvider.cs b/src/Umbraco.Core/Scoping/ScopeProvider.cs index c500a633d0..85e81c1975 100644 --- a/src/Umbraco.Core/Scoping/ScopeProvider.cs +++ b/src/Umbraco.Core/Scoping/ScopeProvider.cs @@ -168,6 +168,7 @@ namespace Umbraco.Core.Scoping } } + // this is for tests exclusively until we have a proper accessor in v8 internal static Func HttpContextItemsGetter { get; set; } private static IDictionary HttpContextItems diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index 0723431ada..868bc484b3 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -61,7 +61,7 @@ namespace Umbraco.Core.Services public int CountPublished(string contentTypeAlias = null) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); return repository.CountPublished(); @@ -70,7 +70,7 @@ namespace Umbraco.Core.Services public int Count(string contentTypeAlias = null) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); return repository.Count(contentTypeAlias); @@ -79,7 +79,7 @@ namespace Umbraco.Core.Services public int CountChildren(int parentId, string contentTypeAlias = null) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); return repository.CountChildren(parentId, contentTypeAlias); @@ -88,7 +88,7 @@ namespace Umbraco.Core.Services public int CountDescendants(int parentId, string contentTypeAlias = null) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); return repository.CountDescendants(parentId, contentTypeAlias); @@ -133,7 +133,7 @@ namespace Umbraco.Core.Services /// public IEnumerable GetPermissionsForEntity(IContent content) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); return repository.GetPermissionsForEntity(content.Id); @@ -161,13 +161,11 @@ namespace Umbraco.Core.Services var parent = GetById(content.ParentId); content.Path = string.Concat(parent.IfNotNull(x => x.Path, content.ParentId.ToString()), ",", content.Id); - // fixme - why are we creating a UOW here and not a SCOPE FFS! - using (var uow = UowProvider.GetUnitOfWork(/*commit: true*/)) // FIXME + we are WRITING audit info FFS! + using (var uow = UowProvider.GetUnitOfWork()) { - // fixme if (uow.Events.DispatchCancelable(Creating, this, new NewEventArgs(content, contentTypeAlias, parentId))) - //if (Creating.IsRaisedEventCancelled(new NewEventArgs(content, contentTypeAlias, parentId), this, uow.Events)) { + uow.Commit(); content.WasCancelled = true; return content; } @@ -175,19 +173,12 @@ namespace Umbraco.Core.Services content.CreatorId = userId; content.WriterId = userId; - // fixme uow.Events.Dispatch(Created, this, new NewEventArgs(content, false, contentTypeAlias, parentId)); - //Created.RaiseEvent(new NewEventArgs(content, false, contentTypeAlias, parentId), this, uow.Events); - // fixme - var auditRepo = RepositoryFactory.CreateAuditRepository(uow); - auditRepo.AddOrUpdate(new AuditItem(content.Id, string.Format("Content '{0}' was created", name), AuditType.New, content.CreatorId)); + Audit(uow, AuditType.New, string.Format("Content '{0}' was created", name), content.CreatorId, content.Id); uow.Commit(); } - // fixme duplicate + NOOOOO not another UOW! - //Audit(AuditType.New, string.Format("Content '{0}' was created", name), content.CreatorId, content.Id); - return content; } @@ -217,6 +208,7 @@ namespace Umbraco.Core.Services { if (uow.Events.DispatchCancelable(Creating, this, new NewEventArgs(content, contentTypeAlias, parent))) { + uow.Commit(); content.WasCancelled = true; return content; } @@ -225,10 +217,10 @@ namespace Umbraco.Core.Services content.WriterId = userId; uow.Events.Dispatch(Created, this, new NewEventArgs(content, false, contentTypeAlias, parent)); - } - // MOVE into the UOW + COMMIT the f*cking thing - Audit(AuditType.New, string.Format("Content '{0}' was created", name), content.CreatorId, content.Id); + Audit(uow, AuditType.New, string.Format("Content '{0}' was created", name), content.CreatorId, content.Id); + uow.Commit(); + } return content; } @@ -257,28 +249,31 @@ namespace Umbraco.Core.Services // out that in these 'WithIdentity' methods, the Saving/Saved events were not fired, wtf. Anyways, they're added now. if (uow.Events.DispatchCancelable(Creating, this, new NewEventArgs(content, contentTypeAlias, parentId))) { + uow.Commit(); content.WasCancelled = true; return content; } if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs(content))) { + uow.Commit(); content.WasCancelled = true; return content; } + var repository = RepositoryFactory.CreateContentRepository(uow); content.CreatorId = userId; content.WriterId = userId; + repository.AddOrUpdate(content); - //Generate a new preview repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c)); - uow.Commit(); uow.Events.Dispatch(Saved, this, new SaveEventArgs(content, false)); uow.Events.Dispatch(Created, this, new NewEventArgs(content, false, contentTypeAlias, parentId)); - } - Audit(AuditType.New, string.Format("Content '{0}' was created with Id {1}", name, content.Id), content.CreatorId, content.Id); + Audit(uow, AuditType.New, string.Format("Content '{0}' was created with Id {1}", name, content.Id), content.CreatorId, content.Id); + uow.Commit(); + } return content; } @@ -309,12 +304,14 @@ namespace Umbraco.Core.Services // out that in these 'WithIdentity' methods, the Saving/Saved events were not fired, wtf. Anyways, they're added now. if (uow.Events.DispatchCancelable(Creating, this, new NewEventArgs(content, contentTypeAlias, parent))) { + uow.Commit(); content.WasCancelled = true; return content; } if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs(content))) { + uow.Commit(); content.WasCancelled = true; return content; } @@ -322,16 +319,16 @@ namespace Umbraco.Core.Services var repository = RepositoryFactory.CreateContentRepository(uow); content.CreatorId = userId; content.WriterId = userId; + repository.AddOrUpdate(content); - //Generate a new preview repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c)); - uow.Commit(); uow.Events.Dispatch(Saved, this, new SaveEventArgs(content, false)); uow.Events.Dispatch(Created, this, new NewEventArgs(content, false, contentTypeAlias, parent)); - } - Audit(AuditType.New, string.Format("Content '{0}' was created with Id {1}", name, content.Id), content.CreatorId, content.Id); + Audit(uow, AuditType.New, string.Format("Content '{0}' was created with Id {1}", name, content.Id), content.CreatorId, content.Id); + uow.Commit(); + } return content; } @@ -343,7 +340,7 @@ namespace Umbraco.Core.Services /// public IContent GetById(int id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); return repository.Get(id); @@ -360,13 +357,12 @@ namespace Umbraco.Core.Services var idsArray = ids.ToArray(); if (idsArray.Length == 0) return Enumerable.Empty(); - using (var uow = UowProvider.GetUnitOfWork()) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); - //ensure that the result has the order based on the ids passed in + // ensure that the result has the order based on the ids passed in var result = repository.GetAll(idsArray); - var content = result.ToDictionary(x => x.Id, x => x); var sortedResult = idsArray.Select(x => @@ -375,7 +371,6 @@ namespace Umbraco.Core.Services return content.TryGetValue(x, out c) ? c : null; }).WhereNotNull(); - uow.Commit(); return sortedResult; } } @@ -387,7 +382,7 @@ namespace Umbraco.Core.Services /// public IContent GetById(Guid key) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); var query = Query.Builder.Where(x => x.Key == key); @@ -403,7 +398,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetContentOfContentType(int id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); var query = Query.Builder.Where(x => x.ContentTypeId == id); @@ -413,7 +408,7 @@ namespace Umbraco.Core.Services internal IEnumerable GetPublishedContentOfContentType(int id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); var query = Query.Builder.Where(x => x.ContentTypeId == id); @@ -428,7 +423,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetByLevel(int level) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); var query = Query.Builder.Where(x => x.Level == level && x.Path.StartsWith(Constants.System.RecycleBinContent.ToInvariantString()) == false); @@ -443,7 +438,7 @@ namespace Umbraco.Core.Services /// An item public IContent GetByVersion(Guid versionId) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); return repository.GetByVersion(versionId); @@ -458,7 +453,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetVersions(int id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); return repository.GetAllVersions(id); @@ -473,7 +468,7 @@ namespace Umbraco.Core.Services /// public IEnumerable GetVersionIds(int id, int maxRows) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); return repository.GetVersionIds(id, maxRows); @@ -505,7 +500,7 @@ namespace Umbraco.Core.Services if (ids.Any() == false) return new List(); - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); return repository.GetAll(ids); @@ -519,7 +514,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetChildren(int id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); var query = Query.Builder.Where(x => x.ParentId == id); @@ -573,7 +568,7 @@ namespace Umbraco.Core.Services Mandate.ParameterCondition(pageIndex >= 0, "pageIndex"); Mandate.ParameterCondition(pageSize > 0, "pageSize"); - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); @@ -634,21 +629,20 @@ namespace Umbraco.Core.Services { Mandate.ParameterCondition(pageIndex >= 0, "pageIndex"); Mandate.ParameterCondition(pageSize > 0, "pageSize"); - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); + // get query - if the id is System Root, then just get all var query = Query.Builder; - //if the id is System Root, then just get all if (id != Constants.System.Root) - { query.Where(x => x.Path.SqlContains(string.Format(",{0},", id), TextColumnType.NVarchar)); - } + + // get filter IQuery filterQuery = null; if (filter.IsNullOrWhiteSpace() == false) - { filterQuery = Query.Builder.Where(x => x.Name.Contains(filter)); - } + return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filterQuery); } } @@ -670,17 +664,15 @@ namespace Umbraco.Core.Services Mandate.ParameterCondition(pageIndex >= 0, "pageIndex"); Mandate.ParameterCondition(pageSize > 0, "pageSize"); - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); + // get query - if the id is System Root, then just get all var query = Query.Builder; - - //if the id is System Root, then just get all if (id != Constants.System.Root) - { query.Where(x => x.Path.SqlContains(string.Format(",{0},", id), TextColumnType.NVarchar)); - } + return repository.GetPagedResultsByQuery(query, pageIndex, pageSize, out totalChildren, orderBy, orderDirection, orderBySystemField, filter); } } @@ -693,7 +685,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetChildrenByName(int parentId, string name) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); @@ -710,11 +702,7 @@ namespace Umbraco.Core.Services public IEnumerable GetDescendants(int id) { var content = GetById(id); - if (content == null) - { - return Enumerable.Empty(); - } - return GetDescendants(content); + return content == null ? Enumerable.Empty() : GetDescendants(content); } /// @@ -728,7 +716,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)); - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); @@ -770,7 +758,7 @@ namespace Umbraco.Core.Services public IContent GetPublishedVersion(int id) { var version = GetVersions(id); - return version.FirstOrDefault(x => x.Published == true); + return version.FirstOrDefault(x => x.Published); } /// @@ -792,7 +780,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetRootContent() { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); @@ -813,7 +801,7 @@ namespace Umbraco.Core.Services _notTrashedQuery = Query.Builder.Where(x => x.Trashed == false); } - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); return repository.GetByPublishedVersion(_notTrashedQuery); @@ -826,7 +814,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetContentForExpiration() { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); var query = Query.Builder.Where(x => x.Published && x.ExpireDate <= DateTime.Now); @@ -840,7 +828,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetContentForRelease() { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); var query = Query.Builder.Where(x => x.Published == false && x.ReleaseDate <= DateTime.Now); @@ -854,7 +842,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetContentInRecycleBin() { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); var query = Query.Builder.Where(x => x.Path.Contains(Constants.System.RecycleBinContent.ToInvariantString())); @@ -876,7 +864,7 @@ namespace Umbraco.Core.Services internal int CountChildren(int id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); var query = Query.Builder.Where(x => x.ParentId == id); @@ -891,7 +879,7 @@ namespace Umbraco.Core.Services /// True if the content has any published version otherwise False public bool HasPublishedVersion(int id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); var query = Query.Builder.Where(x => x.Published == true && x.Id == id && x.Trashed == false); @@ -910,7 +898,7 @@ namespace Umbraco.Core.Services //because if the Parent is publishable then the current content can be Saved and Published if (content.HasIdentity == false) { - IContent parent = GetById(content.ParentId); + var parent = GetById(content.ParentId); return IsPublishable(parent, true); } @@ -1031,6 +1019,7 @@ namespace Umbraco.Core.Services var originalPath = content.Path; if (uow.Events.DispatchCancelable(Trashing, this, new MoveEventArgs(evtMsgs, new MoveEventInfo(content, originalPath, Constants.System.RecycleBinContent)), "Trashing")) { + uow.Commit(); return OperationStatus.Cancelled(evtMsgs); } var moveInfo = new List> @@ -1066,12 +1055,11 @@ namespace Umbraco.Core.Services moveInfo.Add(new MoveEventInfo(descendant, descendant.Path, descendant.ParentId)); } - uow.Commit(); - uow.Events.Dispatch(Trashed, this, new MoveEventArgs(false, evtMsgs, moveInfo.ToArray()), "Trashed"); - } - Audit(AuditType.Move, "Move Content to Recycle Bin performed by user", userId, content.Id); + Audit(uow, AuditType.Move, "Move Content to Recycle Bin performed by user", userId, content.Id); + uow.Commit(); + } return OperationStatus.Success(evtMsgs); } @@ -1192,14 +1180,14 @@ namespace Umbraco.Core.Services using (var uow = UowProvider.GetUnitOfWork()) { - if (raiseEvents) + if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs(asArray, evtMsgs))) { - if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs(asArray, evtMsgs))) - { - return OperationStatus.Cancelled(evtMsgs); - } + uow.Commit(); + return OperationStatus.Cancelled(evtMsgs); } + // todo - understand what's a lock in a scope? + // (though, these locks are refactored in v8) using (new WriteLock(Locker)) { var containsNew = asArray.Any(x => x.HasIdentity == false); @@ -1230,14 +1218,13 @@ namespace Umbraco.Core.Services repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c)); } } - - uow.Commit(); } if (raiseEvents) uow.Events.Dispatch(Saved, this, new SaveEventArgs(asArray, false, evtMsgs)); - Audit(AuditType.Save, "Bulk Save content performed by user", userId == -1 ? 0 : userId, Constants.System.Root); + Audit(uow, AuditType.Save, "Bulk Save content performed by user", userId == -1 ? 0 : userId, Constants.System.Root); + uow.Commit(); return OperationStatus.Success(evtMsgs); } @@ -1262,6 +1249,7 @@ namespace Umbraco.Core.Services { if (uow.Events.DispatchCancelable(Deleting, this, new DeleteEventArgs(content, evtMsgs), "Deleting")) { + uow.Commit(); return OperationStatus.Cancelled(evtMsgs); } @@ -1281,13 +1269,13 @@ namespace Umbraco.Core.Services var repository = RepositoryFactory.CreateContentRepository(uow); repository.Delete(content); - uow.Commit(); var args = new DeleteEventArgs(content, false, evtMsgs); - uow.Events.Dispatch(Deleted, this, args, "Deleted"); // fixme why the event name?! - } + uow.Events.Dispatch(Deleted, this, args, "Deleted"); - Audit(AuditType.Delete, "Delete Content performed by user", userId, content.Id); + Audit(uow, AuditType.Delete, "Delete Content performed by user", userId, content.Id); + uow.Commit(); + } return OperationStatus.Success(evtMsgs); } @@ -1357,11 +1345,6 @@ namespace Umbraco.Core.Services //Determine the items that will need to be recycled (that are children of these content items but not of these content types) var contentToRecycle = this.TrackTrashedForDeleteContentOfTypes(contentTypeIds, rootItems, repository); - // do it INSIDE the UOW because nested UOW kinda should work - // fixme - and then we probably don't need the whole mess? - // nesting UOW works, it's just that the outer one NEEDS to be flushed beforehand - // nevertheless, it would be nicer to create a global scope and inner uow - //move each item to the bin starting with the deepest items foreach (var child in contentToRecycle.OrderByDescending(x => x.Level)) { @@ -1373,12 +1356,10 @@ namespace Umbraco.Core.Services Delete(content, userId); } - uow.Commit(); - - Audit(AuditType.Delete, + Audit(uow, AuditType.Delete, string.Format("Delete Content of Types {0} performed by user", string.Join(",", contentTypeIds)), userId, Constants.System.Root); - + uow.Commit(); } } @@ -1420,17 +1401,17 @@ namespace Umbraco.Core.Services { if (uow.Events.DispatchCancelable(DeletingVersions, this, new DeleteRevisionsEventArgs(id, dateToRetain: versionDate), "DeletingVersions")) { - // fixme - not consistent, shall we commit or not when cancelling?! uow.Commit(); return; } + var repository = RepositoryFactory.CreateContentRepository(uow); repository.DeleteVersions(id, versionDate); - uow.Commit(); uow.Events.Dispatch(DeletedVersions, this, new DeleteRevisionsEventArgs(id, false, dateToRetain: versionDate), "DeletedVersions"); - Audit(AuditType.Delete, "Delete Content by version date performed by user", userId, Constants.System.Root); + Audit(uow, AuditType.Delete, "Delete Content by version date performed by user", userId, Constants.System.Root); + uow.Commit(); } } @@ -1449,7 +1430,10 @@ namespace Umbraco.Core.Services using (var uow = UowProvider.GetUnitOfWork()) { if (uow.Events.DispatchCancelable(DeletingVersions, this, new DeleteRevisionsEventArgs(id, specificVersion: versionId), "DeletingVersions")) + { + uow.Commit(); return; + } if (deletePriorVersions) { @@ -1459,11 +1443,11 @@ namespace Umbraco.Core.Services var repository = RepositoryFactory.CreateContentRepository(uow); repository.DeleteVersion(versionId); - uow.Commit(); uow.Events.Dispatch(DeletedVersions, this, new DeleteRevisionsEventArgs(id, false, specificVersion: versionId), "DeletedVersions"); - Audit(AuditType.Delete, "Delete Content by version performed by user", userId, Constants.System.Root); + Audit(uow, AuditType.Delete, "Delete Content by version performed by user", userId, Constants.System.Root); + uow.Commit(); } } } @@ -1501,13 +1485,13 @@ namespace Umbraco.Core.Services return; } - // fixme - we NEED something for the events - // so even if we don't create a true unit of work (no need) we can create a scope! - // what a spectacular mess - using (IScope scope = UowProvider.ScopeProvider.CreateScope()) + using (var uow = UowProvider.GetUnitOfWork()) { - if (scope.Events.DispatchCancelable(Moving, this, new MoveEventArgs(new MoveEventInfo(content, content.Path, parentId)), "Moving")) + if (uow.Events.DispatchCancelable(Moving, this, new MoveEventArgs(new MoveEventInfo(content, content.Path, parentId)), "Moving")) + { + uow.Commit(); return; + } //used to track all the moved entities to be given to the event var moveInfo = new List>(); @@ -1515,12 +1499,11 @@ namespace Umbraco.Core.Services //call private method that does the recursive moving PerformMove(content, parentId, userId, moveInfo); - scope.Events.Dispatch(Moved, this, new MoveEventArgs(false, moveInfo.ToArray()), "Moved"); + uow.Events.Dispatch(Moved, this, new MoveEventArgs(false, moveInfo.ToArray()), "Moved"); - scope.Complete(); + Audit(uow, AuditType.Move, "Move Content performed by user", userId, content.Id); + uow.Commit(); } - - Audit(AuditType.Move, "Move Content performed by user", userId, content.Id); } } @@ -1531,9 +1514,6 @@ namespace Umbraco.Core.Services { using (new WriteLock(Locker)) { - Dictionary> entities; - List files; - bool success; var nodeObjectType = new Guid(Constants.ObjectTypes.Document); using (var uow = UowProvider.GetUnitOfWork()) @@ -1541,27 +1521,27 @@ namespace Umbraco.Core.Services var repository = RepositoryFactory.CreateContentRepository(uow); //Create a dictionary of ids -> dictionary of property aliases + values - entities = repository.GetEntitiesInRecycleBin() + var entities = repository.GetEntitiesInRecycleBin() .ToDictionary( key => key.Id, val => (IEnumerable)val.Properties); - files = ((ContentRepository)repository).GetFilesInRecycleBinForUploadField(); + var files = ((ContentRepository)repository).GetFilesInRecycleBinForUploadField(); if (uow.Events.DispatchCancelable(EmptyingRecycleBin, this, new RecycleBinEventArgs(nodeObjectType, entities, files))) { - uow.Commit(); // fixme not consistent! // fixme not consistent! + uow.Commit(); return; } - success = repository.EmptyRecycleBin(); + var success = repository.EmptyRecycleBin(); uow.Events.Dispatch(EmptiedRecycleBin, this, new RecycleBinEventArgs(nodeObjectType, entities, files, success)); + + Audit(uow, AuditType.Delete, "Empty Content Recycle Bin performed by user", 0, Constants.System.RecycleBinContent); uow.Commit(); } } - // fixme outside the uow! - Audit(AuditType.Delete, "Empty Content Recycle Bin performed by user", 0, Constants.System.RecycleBinContent); } /// @@ -1601,45 +1581,38 @@ namespace Umbraco.Core.Services // A copy should never be set to published automatically even if the original was. copy.ChangePublishedState(PublishedState.Unpublished); - // fixme mess! - using (var scope = UowProvider.ScopeProvider.CreateScope()) + using (var uow = UowProvider.GetUnitOfWork()) { - using (var uow = UowProvider.GetUnitOfWork()) + if (uow.Events.DispatchCancelable(Copying, this, new CopyEventArgs(content, copy, parentId))) { - if (uow.Events.DispatchCancelable(Copying, this, new CopyEventArgs(content, copy, parentId))) - { - uow.Commit(); - return null; - } - - var repository = RepositoryFactory.CreateContentRepository(uow); - - // Update the create author and last edit author - copy.CreatorId = userId; - copy.WriterId = userId; - - repository.AddOrUpdate(copy); - //add or update a preview - repository.AddOrUpdatePreviewXml(copy, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c)); - uow.Commit(); - - - //Special case for the associated tags - //TODO: Move this to the repository layer in a single transaction! - //don't copy tags data in tags table if the item is in the recycle bin - if (parentId != Constants.System.RecycleBinContent) - { - - var tags = uow.Database.Fetch("WHERE nodeId = @Id", new { Id = content.Id }); - foreach (var tag in tags) - { - uow.Database.Insert(new TagRelationshipDto { NodeId = copy.Id, TagId = tag.TagId, PropertyTypeId = tag.PropertyTypeId }); - } - } - uow.Commit(); + return null; } + var repository = RepositoryFactory.CreateContentRepository(uow); + + // Update the create author and last edit author + copy.CreatorId = userId; + copy.WriterId = userId; + + repository.AddOrUpdate(copy); + repository.AddOrUpdatePreviewXml(copy, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c)); + uow.Commit(); // todo - this should flush, not commit + + //Special case for the associated tags + //TODO: Move this to the repository layer in a single transaction! + //don't copy tags data in tags table if the item is in the recycle bin + if (parentId != Constants.System.RecycleBinContent) + { + var tags = uow.Database.Fetch("WHERE nodeId = @Id", new { Id = content.Id }); + foreach (var tag in tags) + uow.Database.Insert(new TagRelationshipDto + { + NodeId = copy.Id, TagId = tag.TagId, PropertyTypeId = tag.PropertyTypeId + }); + } + uow.Commit(); + if (recursive) { //Look for children and copy those as well @@ -1651,10 +1624,9 @@ namespace Umbraco.Core.Services Copy(child, copy.Id, relateToOriginal, true, userId); } } - scope.Events.Dispatch(Copied, this, new CopyEventArgs(content, copy, false, parentId, relateToOriginal)); - Audit(AuditType.Copy, "Copy Content performed by user", content.WriterId, content.Id); - - scope.Complete(); + uow.Events.Dispatch(Copied, this, new CopyEventArgs(content, copy, false, parentId, relateToOriginal)); + Audit(uow, AuditType.Copy, "Copy Content performed by user", content.WriterId, content.Id); + uow.Commit(); } return copy; @@ -1673,14 +1645,18 @@ namespace Umbraco.Core.Services using (var uow = UowProvider.GetUnitOfWork()) { if (uow.Events.DispatchCancelable(SendingToPublish, this, new SendToPublishEventArgs(content))) + { + uow.Commit(); return false; + } //Save before raising event Save(content, userId); uow.Events.Dispatch(SentToPublish, this, new SendToPublishEventArgs(content, false)); - Audit(AuditType.SendToPublish, "Send to Publish performed by user", content.WriterId, content.Id); + Audit(uow, AuditType.SendToPublish, "Send to Publish performed by user", content.WriterId, content.Id); + uow.Commit(); return true; } @@ -1712,17 +1688,17 @@ namespace Umbraco.Core.Services var repository = RepositoryFactory.CreateContentRepository(uow); - content.WriterId = userId; content.CreatorId = userId; content.ChangePublishedState(PublishedState.Unpublished); repository.AddOrUpdate(content); - //add or update a preview repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c)); - uow.Commit(); + uow.Events.Dispatch(RolledBack, this, new RollbackEventArgs(content, false)); - Audit(AuditType.RollBack, "Content rollback performed by user", content.WriterId, content.Id); + + Audit(uow, AuditType.RollBack, "Content rollback performed by user", content.WriterId, content.Id); + uow.Commit(); } return content; @@ -1750,18 +1726,15 @@ namespace Umbraco.Core.Services using (var uow = UowProvider.GetUnitOfWork()) { var asArray = items.ToArray(); - if (raiseEvents) + if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs(asArray))) { - if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs(asArray))) - { - uow.Commit(); - return false; - } + uow.Commit(); + return false; } var repository = RepositoryFactory.CreateContentRepository(uow); - int i = 0; + var i = 0; foreach (var content in asArray) { //If the current sort order equals that of the content @@ -1797,23 +1770,20 @@ namespace Umbraco.Core.Services repository.AddOrUpdateContentXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c)); } - uow.Commit(); - if (raiseEvents) uow.Events.Dispatch(Saved, this, new SaveEventArgs(asArray, false)); - if (shouldBePublished.Any()) { //TODO: This should not be an inner operation, but if we do this, it cannot raise events and cannot be cancellable! _publishingStrategy.PublishingFinalized(uow, shouldBePublished, false); } + + Audit(uow, AuditType.Sort, "Sorting content performed by user", userId, 0); + uow.Commit(); } } - // fixme - out of uow? - Audit(AuditType.Sort, "Sorting content performed by user", userId, 0); - return true; } @@ -1830,9 +1800,9 @@ namespace Umbraco.Core.Services Mandate.ParameterCondition(pageIndex >= 0, "pageIndex"); Mandate.ParameterCondition(pageSize > 0, "pageSize"); - var uow = UowProvider.GetUnitOfWork(); - using (var repository = RepositoryFactory.CreateContentRepository(uow)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { + var repository = RepositoryFactory.CreateContentRepository(uow); var contents = repository.GetPagedXmlEntriesByPath(path, pageIndex, pageSize, //This order by is VERY important! This allows us to figure out what is implicitly not published, see ContentRepository.BuildXmlCache and // UmbracoContentIndexer.PerformIndexAll which uses the logic based on this sort order @@ -1874,11 +1844,9 @@ namespace Umbraco.Core.Services content => _entitySerializer.Serialize(this, _dataTypeService, _userService, content), contentTypeIds: contentTypeIds.Length == 0 ? null : contentTypeIds); + Audit(uow, AuditType.Publish, "ContentService.RebuildXmlStructures completed, the xml has been regenerated in the database", 0, Constants.System.Root); uow.Commit(); } - - Audit(AuditType.Publish, "ContentService.RebuildXmlStructures completed, the xml has been regenerated in the database", 0, Constants.System.Root); - } #region Internal Methods @@ -1890,7 +1858,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects internal IEnumerable GetPublishedDescendants(IContent content) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentRepository(uow); @@ -1920,14 +1888,10 @@ namespace Umbraco.Core.Services } } - private void Audit(AuditType type, string message, int userId, int objectId) + private void Audit(IScopeUnitOfWork uow, AuditType type, string message, int userId, int objectId) { - using (var uow = UowProvider.GetUnitOfWork()) - { - var auditRepo = RepositoryFactory.CreateAuditRepository(uow); - auditRepo.AddOrUpdate(new AuditItem(objectId, message, type, userId)); - uow.Commit(); - } + var auditRepo = RepositoryFactory.CreateAuditRepository(uow); + auditRepo.AddOrUpdate(new AuditItem(objectId, message, type, userId)); } //TODO: All of this needs to be moved to the repository @@ -2095,12 +2059,12 @@ namespace Umbraco.Core.Services updated.Add(item.Result.ContentItem); } - uow.Commit(); - //Save xml to db and call following method to fire event: _publishingStrategy.PublishingFinalized(uow, updated, false); - Audit(AuditType.Publish, "Publish with Children performed by user", userId, content.Id); + Audit(uow, AuditType.Publish, "Publish with Children performed by user", userId, content.Id); + uow.Commit(); + return publishedOutcome; } } @@ -2145,16 +2109,14 @@ namespace Umbraco.Core.Services repository.ClearPublished(published); repository.DeleteContentXml(content); - uow.Commit(); - //Delete xml from db? and call following method to fire event through PublishingStrategy to update cache if (omitCacheRefresh == false) _publishingStrategy.UnPublishingFinalized(uow, content); + + Audit(uow, AuditType.UnPublish, "UnPublish performed by user", userId, content.Id); + uow.Commit(); } - - Audit(AuditType.UnPublish, "UnPublish performed by user", userId, content.Id); - return Attempt.Succeed(new UnPublishStatus(content, UnPublishedStatusType.Success, evtMsgs)); } @@ -2173,12 +2135,10 @@ namespace Umbraco.Core.Services { using (var uow = UowProvider.GetUnitOfWork()) { - if (raiseEvents) + if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs(content, evtMsgs))) { - if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs(content, evtMsgs))) - { - return Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent, evtMsgs)); - } + uow.Commit(); + return Attempt.Fail(new PublishStatus(content, PublishStatusType.FailedCancelledByEvent, evtMsgs)); } //Has this content item previously been published? If so, we don't need to refresh the children @@ -2221,8 +2181,6 @@ namespace Umbraco.Core.Services content.WriterId = userId; repository.AddOrUpdate(content); - - //Generate a new preview repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c)); if (published) @@ -2231,8 +2189,6 @@ namespace Umbraco.Core.Services repository.AddOrUpdateContentXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c)); } - uow.Commit(); - if (raiseEvents) uow.Events.Dispatch(Saved, this, new SaveEventArgs(content, false, evtMsgs)); @@ -2246,11 +2202,11 @@ namespace Umbraco.Core.Services if (published && previouslyPublished == false && HasChildren(content.Id)) { var descendants = GetPublishedDescendants(content); - _publishingStrategy.PublishingFinalized(uow, descendants, false); } - Audit(AuditType.Publish, "Save and Publish performed by user", userId, content.Id); + Audit(uow, AuditType.Publish, "Save and Publish performed by user", userId, content.Id); + uow.Commit(); return Attempt.If(publishStatus.StatusType == PublishStatusType.Success, publishStatus); } @@ -2272,12 +2228,10 @@ namespace Umbraco.Core.Services { using (var uow = UowProvider.GetUnitOfWork()) { - if (raiseEvents) + if (raiseEvents && uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs(content, evtMsgs))) { - if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs(content, evtMsgs))) - { - return OperationStatus.Cancelled(evtMsgs); - } + uow.Commit(); + return OperationStatus.Cancelled(evtMsgs); } if (string.IsNullOrWhiteSpace(content.Name)) @@ -2302,12 +2256,11 @@ namespace Umbraco.Core.Services //Generate a new preview repository.AddOrUpdatePreviewXml(content, c => _entitySerializer.Serialize(this, _dataTypeService, _userService, c)); - uow.Commit(); - if (raiseEvents) uow.Events.Dispatch(Saved, this, new SaveEventArgs(content, false, evtMsgs)); - Audit(AuditType.Save, "Save Content performed by user", userId, content.Id); + Audit(uow, AuditType.Save, "Save Content performed by user", userId, content.Id); + uow.Commit(); } return OperationStatus.Success(evtMsgs); @@ -2359,7 +2312,8 @@ namespace Umbraco.Core.Services content.Name, content.Id)); return PublishStatusType.FailedPathNotPublished; } - else if (content.ExpireDate.HasValue && content.ExpireDate.Value > DateTime.MinValue && DateTime.Now > content.ExpireDate.Value) + + if (content.ExpireDate.HasValue && content.ExpireDate.Value > DateTime.MinValue && DateTime.Now > content.ExpireDate.Value) { Logger.Info( string.Format( @@ -2367,7 +2321,8 @@ namespace Umbraco.Core.Services content.Name, content.Id)); return PublishStatusType.FailedHasExpired; } - else if (content.ReleaseDate.HasValue && content.ReleaseDate.Value > DateTime.MinValue && content.ReleaseDate.Value > DateTime.Now) + + if (content.ReleaseDate.HasValue && content.ReleaseDate.Value > DateTime.MinValue && content.ReleaseDate.Value > DateTime.Now) { Logger.Info( string.Format( @@ -2396,7 +2351,7 @@ namespace Umbraco.Core.Services private IContentType FindContentTypeByAlias(string contentTypeAlias) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentTypeRepository(uow); @@ -2413,7 +2368,6 @@ namespace Umbraco.Core.Services if (contentType == null) throw new Exception(string.Format("ContentType matching the passed in Alias: '{0}' was null", contentTypeAlias)); - return contentType; } } diff --git a/src/Umbraco.Core/Services/ContentTypeService.cs b/src/Umbraco.Core/Services/ContentTypeService.cs index ce5c6dde34..b21c2acee3 100644 --- a/src/Umbraco.Core/Services/ContentTypeService.cs +++ b/src/Umbraco.Core/Services/ContentTypeService.cs @@ -1,22 +1,15 @@ using System; using System.Collections.Generic; -using System.Data; -using System.Diagnostics; using System.Linq; using System.Text; -using System.Xml.Linq; using System.Threading; -using AutoMapper; -using Umbraco.Core.Auditing; using Umbraco.Core.Configuration; using Umbraco.Core.Events; using Umbraco.Core.Exceptions; using Umbraco.Core.Logging; using Umbraco.Core.Models; -using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence; using Umbraco.Core.Persistence.Querying; -using Umbraco.Core.Persistence.Repositories; using Umbraco.Core.Persistence.UnitOfWork; namespace Umbraco.Core.Services @@ -139,7 +132,7 @@ namespace Umbraco.Core.Services TypedEventHandler> savedEvent, EntityContainer container, Guid containerObjectType, - string objectTypeName, + string objectTypeName, string savedEventName, int userId) { @@ -159,10 +152,9 @@ namespace Umbraco.Core.Services using (var uow = UowProvider.GetUnitOfWork()) { - // fixme - how does it work w/name?! if (uow.Events.DispatchCancelable(savingEvent, this, new SaveEventArgs(container, evtMsgs))) - //if (savingEvent.IsRaisedEventCancelled(new SaveEventArgs(container, evtMsgs), this, UowProvider)) { + uow.Commit(); return OperationStatus.Cancelled(evtMsgs); } @@ -189,7 +181,7 @@ namespace Umbraco.Core.Services private EntityContainer GetContainer(int containerId, Guid containerObjectType) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repo = RepositoryFactory.CreateEntityContainerRepository(uow, containerObjectType); return repo.Get(containerId); @@ -198,7 +190,7 @@ namespace Umbraco.Core.Services public IEnumerable GetMediaTypeContainers(int[] containerIds) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.MediaTypeContainerGuid); return repo.GetAll(containerIds); @@ -207,7 +199,7 @@ namespace Umbraco.Core.Services public IEnumerable GetMediaTypeContainers(string name, int level) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.MediaTypeContainerGuid); return repo.Get(name, level); @@ -236,7 +228,7 @@ namespace Umbraco.Core.Services public IEnumerable GetContentTypeContainers(int[] containerIds) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid); return repo.GetAll(containerIds); @@ -265,7 +257,7 @@ namespace Umbraco.Core.Services private EntityContainer GetContainer(Guid containerId, Guid containerObjectType) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repo = RepositoryFactory.CreateEntityContainerRepository(uow, containerObjectType); return repo.Get(containerId); @@ -274,7 +266,7 @@ namespace Umbraco.Core.Services public IEnumerable GetContentTypeContainers(string name, int level) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid); return repo.Get(name, level); @@ -288,7 +280,11 @@ namespace Umbraco.Core.Services { var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid); var container = repo.Get(containerId); - if (container == null) return OperationStatus.NoOperation(evtMsgs); // fixme commit? + if (container == null) + { + uow.Commit(); + return OperationStatus.NoOperation(evtMsgs); + } if (uow.Events.DispatchCancelable(DeletingContentTypeContainer, this, new DeleteEventArgs(container, evtMsgs))) { @@ -314,7 +310,11 @@ namespace Umbraco.Core.Services var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.MediaTypeContainerGuid); var container = repo.Get(containerId); - if (container == null) return OperationStatus.NoOperation(evtMsgs); // fixme commit? + if (container == null) + { + uow.Commit(); + return OperationStatus.NoOperation(evtMsgs); + } if (uow.Events.DispatchCancelable(DeletingMediaTypeContainer, this, new DeleteEventArgs(container, evtMsgs))) { @@ -340,7 +340,7 @@ namespace Umbraco.Core.Services /// public IEnumerable GetAllPropertyTypeAliases() { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentTypeRepository(uow); return repository.GetAllPropertyTypeAliases(); @@ -357,7 +357,7 @@ namespace Umbraco.Core.Services /// public IEnumerable GetAllContentTypeAliases(params Guid[] objectTypes) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentTypeRepository(uow); return repository.GetAllContentTypeAliases(objectTypes); @@ -454,7 +454,7 @@ namespace Umbraco.Core.Services /// public IContentType GetContentType(int id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentTypeRepository(uow); return repository.Get(id); @@ -468,7 +468,7 @@ namespace Umbraco.Core.Services /// public IContentType GetContentType(string alias) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentTypeRepository(uow); return repository.Get(alias); @@ -482,7 +482,7 @@ namespace Umbraco.Core.Services /// public IContentType GetContentType(Guid id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentTypeRepository(uow); return repository.Get(id); @@ -496,7 +496,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetAllContentTypes(params int[] ids) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentTypeRepository(uow); return repository.GetAll(ids); @@ -510,7 +510,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetAllContentTypes(IEnumerable ids) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentTypeRepository(uow); return repository.GetAll(ids.ToArray()); @@ -524,7 +524,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetContentTypeChildren(int id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentTypeRepository(uow); var query = Query.Builder.Where(x => x.ParentId == id); @@ -539,7 +539,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetContentTypeChildren(Guid id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentTypeRepository(uow); @@ -557,7 +557,7 @@ namespace Umbraco.Core.Services /// True if the content type has any children otherwise False public bool HasChildren(int id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentTypeRepository(uow); @@ -573,7 +573,7 @@ namespace Umbraco.Core.Services /// True if the content type has any children otherwise False public bool HasChildren(Guid id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentTypeRepository(uow); @@ -584,6 +584,27 @@ namespace Umbraco.Core.Services } } + public override IEnumerable GetDescendants(IContentTypeBase contentType) + { + var ctype = contentType as IContentType; + if (ctype != null) return GetDescendants(ctype); + var mtype = contentType as IMediaType; + if (mtype != null) return GetDescendants(mtype); + return Enumerable.Empty(); + } + + public IEnumerable GetDescendants(IContentType contentType) + { + return GetContentTypeChildren(contentType.Id) + .SelectRecursive(type => GetContentTypeChildren(type.Id)); + } + + public IEnumerable GetDescendants(IMediaType contentType) + { + return GetMediaTypeChildren(contentType.Id) + .SelectRecursive(type => GetMediaTypeChildren(type.Id)); + } + /// /// This is called after an IContentType is saved and is used to update the content xml structures in the database /// if they are required to be updated. @@ -591,42 +612,39 @@ namespace Umbraco.Core.Services /// A tuple of a content type and a boolean indicating if it is new (HasIdentity was false before committing) private void UpdateContentXmlStructure(params IContentTypeBase[] contentTypes) { - var toUpdate = GetContentTypesForXmlUpdates(contentTypes).ToArray(); - if (toUpdate.Any()) + if (toUpdate.Any() == false) return; + + var firstType = toUpdate.First(); + //if it is a content type then call the rebuilding methods or content + if (firstType is IContentType) { - var firstType = toUpdate.First(); - //if it is a content type then call the rebuilding methods or content - if (firstType is IContentType) + var typedContentService = _contentService as ContentService; + if (typedContentService != null) { - var typedContentService = _contentService as ContentService; - if (typedContentService != null) - { - typedContentService.RePublishAll(toUpdate.Select(x => x.Id).ToArray()); - } - else - { - //this should never occur, the content service should always be typed but we'll check anyways. - _contentService.RePublishAll(); - } + typedContentService.RePublishAll(toUpdate.Select(x => x.Id).ToArray()); } - else if (firstType is IMediaType) + else { - //if it is a media type then call the rebuilding methods for media - var typedContentService = _mediaService as MediaService; - if (typedContentService != null) - { - typedContentService.RebuildXmlStructures(toUpdate.Select(x => x.Id).ToArray()); - } + //this should never occur, the content service should always be typed but we'll check anyways. + _contentService.RePublishAll(); + } + } + else if (firstType is IMediaType) + { + //if it is a media type then call the rebuilding methods for media + var typedContentService = _mediaService as MediaService; + if (typedContentService != null) + { + typedContentService.RebuildXmlStructures(toUpdate.Select(x => x.Id).ToArray()); } } - } public int CountContentTypes() { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateContentTypeRepository(uow); return repository.Count(Query.Builder); @@ -635,7 +653,7 @@ namespace Umbraco.Core.Services public int CountMediaTypes() { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateMediaTypeRepository(uow); return repository.Count(Query.Builder); @@ -753,16 +771,15 @@ namespace Umbraco.Core.Services repository.AddOrUpdate(contentType); uow.Commit(); - } - UpdateContentXmlStructure(contentType); // fixme wtf here? + UpdateContentXmlStructure(contentType); + + uow.Events.Dispatch(SavedContentType, this, new SaveEventArgs(contentType, false)); + + Audit(uow, AuditType.Save, "Save ContentType performed by user", userId, contentType.Id); + uow.Commit(); + } } - using (var scope = UowProvider.ScopeProvider.CreateScope()) // fixme what a mess - { - scope.Events.Dispatch(SavedContentType, this, new SaveEventArgs(contentType, false)); - scope.Complete(); - } - Audit(AuditType.Save, "Save ContentType performed by user", userId, contentType.Id); } /// @@ -783,7 +800,7 @@ namespace Umbraco.Core.Services uow.Commit(); return; } - + var repository = RepositoryFactory.CreateContentTypeRepository(uow); foreach (var contentType in asArray) @@ -798,16 +815,15 @@ namespace Umbraco.Core.Services //save it all in one go uow.Commit(); - } - UpdateContentXmlStructure(asArray.Cast().ToArray()); // fixme wtf + UpdateContentXmlStructure(asArray.Cast().ToArray()); + + uow.Events.Dispatch(SavedContentType, this, new SaveEventArgs(asArray, false)); + + Audit(uow, AuditType.Save, "Save ContentTypes performed by user", userId, -1); + uow.Commit(); + } } - using (var scope = UowProvider.ScopeProvider.CreateScope()) // fixme what a mess - { - scope.Events.Dispatch(SavedContentType, this, new SaveEventArgs(asArray, false)); - scope.Complete(); - } - Audit(AuditType.Save, "Save ContentTypes performed by user", userId, -1); } /// @@ -817,7 +833,7 @@ namespace Umbraco.Core.Services /// Optional id of the user issueing the delete /// Deleting a will delete all the objects based on this public void Delete(IContentType contentType, int userId = 0) - { + { using (new WriteLock(Locker)) { using (var uow = UowProvider.GetUnitOfWork()) @@ -829,20 +845,20 @@ namespace Umbraco.Core.Services } var repository = RepositoryFactory.CreateContentTypeRepository(uow); - + //If we are deleting this content type, we are also deleting it's descendents! - var deletedContentTypes = new List() {contentType}; - deletedContentTypes.AddRange(contentType.Descendants((IContentTypeService)this).OfType()); + var deletedContentTypes = new List {contentType}; + deletedContentTypes.AddRange(GetDescendants(contentType)); _contentService.DeleteContentOfTypes(deletedContentTypes.Select(x => x.Id), userId); - + repository.Delete(contentType); - uow.Commit(); uow.Events.Dispatch(DeletedContentType, this, new DeleteEventArgs(deletedContentTypes.DistinctBy(x => x.Id), false)); - } - Audit(AuditType.Delete, string.Format("Delete ContentType performed by user"), userId, contentType.Id); + Audit(uow, AuditType.Delete, string.Format("Delete ContentType performed by user"), userId, contentType.Id); + uow.Commit(); + } } } @@ -857,7 +873,7 @@ namespace Umbraco.Core.Services public void Delete(IEnumerable contentTypes, int userId = 0) { var asArray = contentTypes.ToArray(); - + using (new WriteLock(Locker)) { using (var uow = UowProvider.GetUnitOfWork()) @@ -874,22 +890,21 @@ namespace Umbraco.Core.Services var deletedContentTypes = new List(asArray); foreach (var contentType in asArray) { - deletedContentTypes.AddRange(contentType.Descendants((IContentTypeService)this).OfType()); + deletedContentTypes.AddRange(GetDescendants(contentType)); } - _contentService.DeleteContentOfTypes(deletedContentTypes.Select(x => x.Id), userId); + _contentService.DeleteContentOfTypes(deletedContentTypes.Select(x => x.Id), userId); foreach (var contentType in asArray) { repository.Delete(contentType); } - uow.Commit(); - uow.Events.Dispatch(DeletedContentType, this, new DeleteEventArgs(deletedContentTypes.DistinctBy(x => x.Id), false)); - } - Audit(AuditType.Delete, string.Format("Delete ContentTypes performed by user"), userId, -1); + Audit(uow, AuditType.Delete, string.Format("Delete ContentTypes performed by user"), userId, -1); + uow.Commit(); + } } } @@ -900,7 +915,7 @@ namespace Umbraco.Core.Services /// public IMediaType GetMediaType(int id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateMediaTypeRepository(uow); return repository.Get(id); @@ -914,7 +929,7 @@ namespace Umbraco.Core.Services /// public IMediaType GetMediaType(string alias) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateMediaTypeRepository(uow); return repository.Get(alias); @@ -928,7 +943,7 @@ namespace Umbraco.Core.Services /// public IMediaType GetMediaType(Guid id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateMediaTypeRepository(uow); return repository.Get(id); @@ -942,7 +957,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetAllMediaTypes(params int[] ids) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateMediaTypeRepository(uow); return repository.GetAll(ids); @@ -956,7 +971,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetAllMediaTypes(IEnumerable ids) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateMediaTypeRepository(uow); return repository.GetAll(ids.ToArray()); @@ -970,7 +985,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetMediaTypeChildren(int id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateMediaTypeRepository(uow); var query = Query.Builder.Where(x => x.ParentId == id); @@ -985,7 +1000,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetMediaTypeChildren(Guid id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateMediaTypeRepository(uow); var found = GetMediaType(id); @@ -1002,7 +1017,7 @@ namespace Umbraco.Core.Services /// True if the media type has any children otherwise False public bool MediaTypeHasChildren(int id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateMediaTypeRepository(uow); var query = Query.Builder.Where(x => x.ParentId == id); @@ -1017,7 +1032,7 @@ namespace Umbraco.Core.Services /// True if the media type has any children otherwise False public bool MediaTypeHasChildren(Guid id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateMediaTypeRepository(uow); var found = GetMediaType(id); @@ -1035,7 +1050,10 @@ namespace Umbraco.Core.Services using (var uow = UowProvider.GetUnitOfWork()) { if (uow.Events.DispatchCancelable(MovingMediaType, this, new MoveEventArgs(evtMsgs, new MoveEventInfo(toMove, toMove.Path, containerId)))) + { + uow.Commit(); return Attempt.Fail(new OperationStatus(MoveOperationStatusType.FailedCancelledByEvent, evtMsgs)); + } var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.MediaTypeContainerGuid); var repository = RepositoryFactory.CreateMediaTypeRepository(uow); @@ -1052,8 +1070,8 @@ namespace Umbraco.Core.Services } catch (DataOperationException ex) { - return Attempt.Fail( - new OperationStatus(ex.Operation, evtMsgs)); + uow.Commit(); + return Attempt.Fail(new OperationStatus(ex.Operation, evtMsgs)); } uow.Commit(); uow.Events.Dispatch(MovedMediaType, this, new MoveEventArgs(false, evtMsgs, moveInfo.ToArray())); @@ -1071,7 +1089,10 @@ namespace Umbraco.Core.Services using (var uow = UowProvider.GetUnitOfWork()) { if (uow.Events.DispatchCancelable(MovingContentType, this, new MoveEventArgs(evtMsgs, new MoveEventInfo(toMove, toMove.Path, containerId)))) + { + uow.Commit(); return Attempt.Fail(new OperationStatus(MoveOperationStatusType.FailedCancelledByEvent, evtMsgs)); + } var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DocumentTypeContainerGuid); var repository = RepositoryFactory.CreateContentTypeRepository(uow); @@ -1088,8 +1109,8 @@ namespace Umbraco.Core.Services } catch (DataOperationException ex) { - return Attempt.Fail( - new OperationStatus(ex.Operation, evtMsgs)); + uow.Commit(); + return Attempt.Fail(new OperationStatus(ex.Operation, evtMsgs)); } uow.Commit(); uow.Events.Dispatch(MovedContentType, this, new MoveEventArgs(false, evtMsgs, moveInfo.ToArray())); @@ -1135,6 +1156,7 @@ namespace Umbraco.Core.Services } catch (DataOperationException ex) { + uow.Commit(); return Attempt.Fail(new OperationStatus(null, ex.Operation, evtMsgs)); } uow.Commit(); @@ -1179,6 +1201,7 @@ namespace Umbraco.Core.Services } catch (DataOperationException ex) { + uow.Commit(); return Attempt.Fail(new OperationStatus(null, ex.Operation, evtMsgs)); } uow.Commit(); @@ -1203,23 +1226,21 @@ namespace Umbraco.Core.Services uow.Commit(); return; } - + var repository = RepositoryFactory.CreateMediaTypeRepository(uow); ValidateLocked(mediaType); // throws if invalid mediaType.CreatorId = userId; repository.AddOrUpdate(mediaType); uow.Commit(); - } - UpdateContentXmlStructure(mediaType); // fixme wtf + UpdateContentXmlStructure(mediaType); - using (var scope = UowProvider.ScopeProvider.CreateScope()) // fixme what a mess - { - scope.Events.Dispatch(SavedMediaType, this, new SaveEventArgs(mediaType, false)); - scope.Complete(); + uow.Events.Dispatch(SavedMediaType, this, new SaveEventArgs(mediaType, false)); + + Audit(uow, AuditType.Save, "Save MediaType performed by user", userId, mediaType.Id); + uow.Commit(); } - Audit(AuditType.Save, "Save MediaType performed by user", userId, mediaType.Id); } } @@ -1231,7 +1252,7 @@ namespace Umbraco.Core.Services public void Save(IEnumerable mediaTypes, int userId = 0) { var asArray = mediaTypes.ToArray(); - + using (new WriteLock(Locker)) { using (var uow = UowProvider.GetUnitOfWork()) @@ -1241,7 +1262,7 @@ namespace Umbraco.Core.Services uow.Commit(); return; } - + var repository = RepositoryFactory.CreateMediaTypeRepository(uow); foreach (var mediaType in asArray) @@ -1256,15 +1277,14 @@ namespace Umbraco.Core.Services //save it all in one go uow.Commit(); - } - UpdateContentXmlStructure(asArray.Cast().ToArray()); // fixme wtf - using (var scope = UowProvider.ScopeProvider.CreateScope()) // fixme what a mess - { - scope.Events.Dispatch(SavedMediaType, this, new SaveEventArgs(asArray, false)); - scope.Complete(); + UpdateContentXmlStructure(asArray.Cast().ToArray()); + + uow.Events.Dispatch(SavedMediaType, this, new SaveEventArgs(asArray, false)); + + Audit(uow, AuditType.Save, "Save MediaTypes performed by user", userId, -1); + uow.Commit(); } - Audit(AuditType.Save, "Save MediaTypes performed by user", userId, -1); } } @@ -1292,17 +1312,17 @@ namespace Umbraco.Core.Services //If we are deleting this content type, we are also deleting it's descendents! var deletedMediaTypes = new List { mediaType }; - deletedMediaTypes.AddRange(mediaType.Descendants((IContentTypeService)this).OfType()); + deletedMediaTypes.AddRange(GetDescendants(mediaType)); _mediaService.DeleteMediaOfTypes(deletedMediaTypes.Select(x => x.Id), userId); repository.Delete(mediaType); - uow.Commit(); uow.Events.Dispatch(DeletedMediaType, this, new DeleteEventArgs(deletedMediaTypes.DistinctBy(x => x.Id), false)); - } - Audit(AuditType.Delete, "Delete MediaType performed by user", userId, mediaType.Id); + Audit(uow, AuditType.Delete, "Delete MediaType performed by user", userId, mediaType.Id); + uow.Commit(); + } } } @@ -1317,7 +1337,7 @@ namespace Umbraco.Core.Services //TODO: Share all of this logic with the Delete IContentType methods, no need for code duplication var asArray = mediaTypes.ToArray(); - + using (new WriteLock(Locker)) { using (var uow = UowProvider.GetUnitOfWork()) @@ -1329,12 +1349,12 @@ namespace Umbraco.Core.Services } var repository = RepositoryFactory.CreateMediaTypeRepository(uow); - + //If we are deleting this content type, we are also deleting it's descendents! var deletedMediaTypes = new List(asArray); foreach (var mediaType in asArray) { - deletedMediaTypes.AddRange(mediaType.Descendants((IContentTypeService)this).OfType()); + deletedMediaTypes.AddRange(GetDescendants(mediaType)); } _mediaService.DeleteMediaOfTypes(deletedMediaTypes.Select(x => x.Id), userId); @@ -1344,12 +1364,11 @@ namespace Umbraco.Core.Services repository.Delete(mediaType); } - uow.Commit(); - uow.Events.Dispatch(DeletedMediaType, this, new DeleteEventArgs(deletedMediaTypes.DistinctBy(x => x.Id), false)); - } - Audit(AuditType.Delete, "Delete MediaTypes performed by user", userId, -1); + Audit(uow, AuditType.Delete, "Delete MediaTypes performed by user", userId, -1); + uow.Commit(); + } } } @@ -1408,14 +1427,10 @@ namespace Umbraco.Core.Services return dtd.ToString(); } - private void Audit(AuditType type, string message, int userId, int objectId) + private void Audit(IScopeUnitOfWork uow, AuditType type, string message, int userId, int objectId) { - using (var uow = UowProvider.GetUnitOfWork()) - { - var auditRepo = RepositoryFactory.CreateAuditRepository(uow); - auditRepo.AddOrUpdate(new AuditItem(objectId, message, type, userId)); - uow.Commit(); - } + var auditRepo = RepositoryFactory.CreateAuditRepository(uow); + auditRepo.AddOrUpdate(new AuditItem(objectId, message, type, userId)); } #region Event Handlers diff --git a/src/Umbraco.Core/Services/ContentTypeServiceBase.cs b/src/Umbraco.Core/Services/ContentTypeServiceBase.cs index 8b8103be6e..28bb58fb5a 100644 --- a/src/Umbraco.Core/Services/ContentTypeServiceBase.cs +++ b/src/Umbraco.Core/Services/ContentTypeServiceBase.cs @@ -13,9 +13,8 @@ namespace Umbraco.Core.Services { public ContentTypeServiceBase(IDatabaseUnitOfWorkProvider provider, RepositoryFactory repositoryFactory, ILogger logger, IEventMessagesFactory eventMessagesFactory) : base(provider, repositoryFactory, logger, eventMessagesFactory) - { - } - + { } + /// /// This is called after an content type is saved and is used to update the content xml structures in the database /// if they are required to be updated. @@ -33,7 +32,7 @@ namespace Umbraco.Core.Services // - a content type changes it's alias OR // - if a content type has it's property removed OR // - if a content type has a property whose alias has changed - //here we need to check if the alias of the content type changed or if one of the properties was removed. + //here we need to check if the alias of the content type changed or if one of the properties was removed. var dirty = contentType as IRememberBeingDirty; if (dirty == null) continue; @@ -50,25 +49,30 @@ namespace Umbraco.Core.Services && (dirty.WasPropertyDirty("Alias") || dirty.WasPropertyDirty("HasPropertyTypeBeenRemoved") || hasAnyPropertiesChangedAlias)) { //If the alias was changed then we only need to update the xml structures for content of the current content type. - //If a property was deleted or a property alias was changed then we need to update the xml structures for any + //If a property was deleted or a property alias was changed then we need to update the xml structures for any // content of the current content type and any of the content type's child content types. if (dirty.WasPropertyDirty("Alias") && dirty.WasPropertyDirty("HasPropertyTypeBeenRemoved") == false && hasAnyPropertiesChangedAlias == false) { - //if only the alias changed then only update the current content type + //if only the alias changed then only update the current content type toUpdate.Add(contentType); } else { //if a property was deleted or alias changed, then update all content of the current content type - // and all of it's desscendant doc types. - toUpdate.AddRange(contentType.DescendantsAndSelf(this)); + // and all of it's desscendant doc types. + toUpdate.Add(contentType); + toUpdate.AddRange(GetDescendants(contentType)); } } } return toUpdate; + } + public virtual IEnumerable GetDescendants(IContentTypeBase contentType) + { + return Enumerable.Empty(); } } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/DataTypeService.cs b/src/Umbraco.Core/Services/DataTypeService.cs index cd904a813f..a33949fb6d 100644 --- a/src/Umbraco.Core/Services/DataTypeService.cs +++ b/src/Umbraco.Core/Services/DataTypeService.cs @@ -66,7 +66,7 @@ namespace Umbraco.Core.Services public EntityContainer GetContainer(int containerId) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid); return repo.Get(containerId); @@ -75,7 +75,7 @@ namespace Umbraco.Core.Services public EntityContainer GetContainer(Guid containerId) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid); return repo.Get(containerId); @@ -84,7 +84,7 @@ namespace Umbraco.Core.Services public IEnumerable GetContainers(string name, int level) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid); return repo.Get(name, level); @@ -108,7 +108,7 @@ namespace Umbraco.Core.Services public IEnumerable GetContainers(int[] containerIds) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repo = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid); return repo.GetAll(containerIds); @@ -181,7 +181,7 @@ namespace Umbraco.Core.Services /// public IDataTypeDefinition GetDataTypeDefinitionByName(string name) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow); return repository.GetByQuery(new Query().Where(x => x.Name == name)).FirstOrDefault(); @@ -195,7 +195,7 @@ namespace Umbraco.Core.Services /// public IDataTypeDefinition GetDataTypeDefinitionById(int id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow); return repository.Get(id); @@ -209,7 +209,7 @@ namespace Umbraco.Core.Services /// public IDataTypeDefinition GetDataTypeDefinitionById(Guid id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow); var query = Query.Builder.Where(x => x.Key == id); @@ -238,7 +238,7 @@ namespace Umbraco.Core.Services /// Collection of objects with a matching contorl id public IEnumerable GetDataTypeDefinitionByPropertyEditorAlias(string propertyEditorAlias) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow); var query = Query.Builder.Where(x => x.PropertyEditorAlias == propertyEditorAlias); @@ -253,7 +253,7 @@ namespace Umbraco.Core.Services /// An enumerable list of objects public IEnumerable GetAllDataTypeDefinitions(params int[] ids) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow); return repository.GetAll(ids); @@ -267,7 +267,7 @@ namespace Umbraco.Core.Services /// An enumerable list of string values public IEnumerable GetPreValuesByDataTypeId(int id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow); //now convert the collection to a string list @@ -284,7 +284,7 @@ namespace Umbraco.Core.Services /// public PreValueCollection GetPreValuesCollectionByDataTypeId(int id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow); return repository.GetPreValuesCollectionByDataTypeId(id); @@ -298,7 +298,7 @@ namespace Umbraco.Core.Services /// PreValue as a string public string GetPreValueAsString(int id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow); return repository.GetPreValueAsString(id); @@ -313,7 +313,10 @@ namespace Umbraco.Core.Services using (var uow = UowProvider.GetUnitOfWork()) { if (uow.Events.DispatchCancelable(Moving, this, new MoveEventArgs(evtMsgs, new MoveEventInfo(toMove, toMove.Path, parentId)))) + { + uow.Commit(); return Attempt.Fail(new OperationStatus(MoveOperationStatusType.FailedCancelledByEvent, evtMsgs)); + } var containerRepository = RepositoryFactory.CreateEntityContainerRepository(uow, Constants.ObjectTypes.DataTypeContainerGuid); var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow); @@ -366,13 +369,12 @@ namespace Umbraco.Core.Services dataTypeDefinition.CreatorId = userId; repository.AddOrUpdate(dataTypeDefinition); - uow.Commit(); uow.Events.Dispatch(Saved, this, new SaveEventArgs(dataTypeDefinition, false)); - } - // FIXME transaction! - Audit(AuditType.Save, "Save DataTypeDefinition performed by user", userId, dataTypeDefinition.Id); + Audit(uow, AuditType.Save, "Save DataTypeDefinition performed by user", userId, dataTypeDefinition.Id); + uow.Commit(); + } } /// @@ -411,13 +413,13 @@ namespace Umbraco.Core.Services dataTypeDefinition.CreatorId = userId; repository.AddOrUpdate(dataTypeDefinition); } - uow.Commit(); if (raiseEvents) uow.Events.Dispatch(Saved, this, new SaveEventArgs(dataTypeDefinitions, false)); - } - Audit(AuditType.Save, string.Format("Save DataTypeDefinition performed by user"), userId, -1); + Audit(uow, AuditType.Save, string.Format("Save DataTypeDefinition performed by user"), userId, -1); + uow.Commit(); + } } /// @@ -487,7 +489,6 @@ namespace Umbraco.Core.Services using (var uow = UowProvider.GetUnitOfWork()) { var repository = RepositoryFactory.CreateDataTypeDefinitionRepository(uow); - repository.AddOrUpdatePreValues(dataTypeDefinition, values); uow.Commit(); } @@ -504,7 +505,10 @@ namespace Umbraco.Core.Services using (var uow = UowProvider.GetUnitOfWork()) { if (uow.Events.DispatchCancelable(Saving, this, new SaveEventArgs(dataTypeDefinition))) + { + uow.Commit(); return; + } // if preValues contain the data type, override the data type definition accordingly if (values != null && values.ContainsKey(Constants.PropertyEditors.PreValueKeys.DataValueType)) @@ -520,12 +524,11 @@ namespace Umbraco.Core.Services //add/update the prevalues repository.AddOrUpdatePreValues(dataTypeDefinition, values); + Audit(uow, AuditType.Save, string.Format("Save DataTypeDefinition performed by user"), userId, dataTypeDefinition.Id); uow.Commit(); uow.Events.Dispatch(Saved, this, new SaveEventArgs(dataTypeDefinition, false)); } - - Audit(AuditType.Save, string.Format("Save DataTypeDefinition performed by user"), userId, dataTypeDefinition.Id); } /// @@ -548,12 +551,11 @@ namespace Umbraco.Core.Services repository.Delete(dataTypeDefinition); + Audit(uow, AuditType.Delete, "Delete DataTypeDefinition performed by user", userId, dataTypeDefinition.Id); uow.Commit(); uow.Events.Dispatch(Deleted, this, new DeleteEventArgs(dataTypeDefinition, false)); } - - Audit(AuditType.Delete, "Delete DataTypeDefinition performed by user", userId, dataTypeDefinition.Id); } /// @@ -577,14 +579,10 @@ namespace Umbraco.Core.Services return DataTypesResolver.Current.DataTypes; } - private void Audit(AuditType type, string message, int userId, int objectId) + private void Audit(IScopeUnitOfWork uow, AuditType type, string message, int userId, int objectId) { - using (var uow = UowProvider.GetUnitOfWork()) - { - var auditRepo = RepositoryFactory.CreateAuditRepository(uow); - auditRepo.AddOrUpdate(new AuditItem(objectId, message, type, userId)); - uow.Commit(); - } + var auditRepo = RepositoryFactory.CreateAuditRepository(uow); + auditRepo.AddOrUpdate(new AuditItem(objectId, message, type, userId)); } #region Event Handlers @@ -624,7 +622,5 @@ namespace Umbraco.Core.Services /// public static event TypedEventHandler> Moved; #endregion - - } } \ No newline at end of file diff --git a/src/Umbraco.Core/Services/DomainService.cs b/src/Umbraco.Core/Services/DomainService.cs index 64232fc5ab..2248fc0c1f 100644 --- a/src/Umbraco.Core/Services/DomainService.cs +++ b/src/Umbraco.Core/Services/DomainService.cs @@ -19,7 +19,7 @@ namespace Umbraco.Core.Services public bool Exists(string domainName) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repo = RepositoryFactory.CreateDomainRepository(uow); return repo.Exists(domainName); @@ -49,7 +49,7 @@ namespace Umbraco.Core.Services public IDomain GetByName(string name) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateDomainRepository(uow); return repository.GetByName(name); @@ -58,7 +58,7 @@ namespace Umbraco.Core.Services public IDomain GetById(int id) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repo = RepositoryFactory.CreateDomainRepository(uow); return repo.Get(id); @@ -67,7 +67,7 @@ namespace Umbraco.Core.Services public IEnumerable GetAll(bool includeWildcards) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repo = RepositoryFactory.CreateDomainRepository(uow); return repo.GetAll(includeWildcards); @@ -76,7 +76,7 @@ namespace Umbraco.Core.Services public IEnumerable GetAssignedDomains(int contentId, bool includeWildcards) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repo = RepositoryFactory.CreateDomainRepository(uow); return repo.GetAssignedDomains(contentId, includeWildcards); diff --git a/src/Umbraco.Core/Services/FileService.cs b/src/Umbraco.Core/Services/FileService.cs index ec886d788d..a8a16de0e0 100644 --- a/src/Umbraco.Core/Services/FileService.cs +++ b/src/Umbraco.Core/Services/FileService.cs @@ -50,7 +50,7 @@ namespace Umbraco.Core.Services /// An enumerable list of objects public IEnumerable GetStylesheets(params string[] names) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { // FIXME is it ok to use the same UOW here twice? // review everywhere in this file!! @@ -66,7 +66,7 @@ namespace Umbraco.Core.Services /// A object public Stylesheet GetStylesheetByName(string name) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateStylesheetRepository(uow, uow); return repository.Get(name); @@ -90,11 +90,12 @@ namespace Umbraco.Core.Services var repository = RepositoryFactory.CreateStylesheetRepository(uow, uow); repository.AddOrUpdate(stylesheet); - uow.Commit(); - uow.Events.Dispatch(SavedStylesheet, this, new SaveEventArgs(stylesheet, false)); - } - Audit(AuditType.Save, "Save Stylesheet performed by user", userId, -1); + uow.Events.Dispatch(SavedStylesheet, this, new SaveEventArgs(stylesheet, false)); + + Audit(uow, AuditType.Save, "Save Stylesheet performed by user", userId, -1); + uow.Commit(); + } } /// @@ -121,12 +122,12 @@ namespace Umbraco.Core.Services } repository.Delete(stylesheet); - uow.Commit(); uow.Events.Dispatch(DeletedStylesheet, this, new DeleteEventArgs(stylesheet, false)); - } - Audit(AuditType.Delete, string.Format("Delete Stylesheet performed by user"), userId, -1); + Audit(uow, AuditType.Delete, string.Format("Delete Stylesheet performed by user"), userId, -1); + uow.Commit(); + } } /// @@ -136,7 +137,7 @@ namespace Umbraco.Core.Services /// True if Stylesheet is valid, otherwise false public bool ValidateStylesheet(Stylesheet stylesheet) { - using (var uow = UowProvider.GetUnitOfWork(commit: true)) + using (var uow = UowProvider.GetUnitOfWork(readOnly: true)) { var repository = RepositoryFactory.CreateStylesheetRepository(uow, uow); return repository.ValidateStylesheet(stylesheet); @@ -152,7 +153,7 @@ namespace Umbraco.Core.Services /// An enumerable list of objects public IEnumerable