diff --git a/src/Umbraco.Core/Cache/CacheHelper.cs b/src/Umbraco.Core/Cache/CacheHelper.cs index ac2840a59f..a85285e427 100644 --- a/src/Umbraco.Core/Cache/CacheHelper.cs +++ b/src/Umbraco.Core/Cache/CacheHelper.cs @@ -11,12 +11,7 @@ namespace Umbraco.Core.Cache /// public class CacheHelper { - private static readonly ICacheProvider NullRequestCache = new NullCacheProvider(); - private static readonly ICacheProvider NullStaticCache = new NullCacheProvider(); - private static readonly IRuntimeCacheProvider NullRuntimeCache = new NullCacheProvider(); - private static readonly IsolatedRuntimeCache NullIsolatedCache = new IsolatedRuntimeCache(_ => NullRuntimeCache); - - public static CacheHelper NoCache { get; } = new CacheHelper(NullRuntimeCache, NullStaticCache, NullRequestCache, NullIsolatedCache); + public static CacheHelper NoCache { get; } = new CacheHelper(NullCacheProvider.Instance, NullCacheProvider.Instance, NullCacheProvider.Instance, new IsolatedRuntimeCache(_ => NullCacheProvider.Instance)); /// /// Creates a cache helper with disabled caches @@ -30,7 +25,7 @@ namespace Umbraco.Core.Cache // do *not* return NoCache // NoCache is a special instance that is detected by RepositoryBase and disables all cache policies // CreateDisabledCacheHelper is used in tests to use no cache, *but* keep all cache policies - return new CacheHelper(NullRuntimeCache, NullStaticCache, NullRequestCache, NullIsolatedCache); + return new CacheHelper(NullCacheProvider.Instance, NullCacheProvider.Instance, NullCacheProvider.Instance, new IsolatedRuntimeCache(_ => NullCacheProvider.Instance)); } /// diff --git a/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs index 3833da1618..4e668f064d 100644 --- a/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs +++ b/src/Umbraco.Core/Cache/DefaultRepositoryCachePolicy.cs @@ -23,17 +23,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) + public DefaultRepositoryCachePolicy(IRuntimeCacheProvider cache, IScopeAccessor scopeAccessor, RepositoryCachePolicyOptions options) + : base(cache, scopeAccessor) { _options = options ?? throw new ArgumentNullException(nameof(options)); } - public override IRepositoryCachePolicy Scoped(IRuntimeCacheProvider runtimeCache, IScope scope) - { - return new ScopedRepositoryCachePolicy(this, runtimeCache, scope); - } - protected string GetEntityCacheKey(object id) { if (id == null) throw new ArgumentNullException(nameof(id)); diff --git a/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs index 00a5a7fe66..d28896e201 100644 --- a/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs +++ b/src/Umbraco.Core/Cache/FullDataSetRepositoryCachePolicy.cs @@ -24,18 +24,13 @@ namespace Umbraco.Core.Cache private readonly Func _entityGetId; private readonly bool _expires; - public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache, Func entityGetId, bool expires) - : base(cache) + public FullDataSetRepositoryCachePolicy(IRuntimeCacheProvider cache, IScopeAccessor scopeAccessor, Func entityGetId, bool expires) + : base(cache, scopeAccessor) { _entityGetId = entityGetId; _expires = expires; } - public override IRepositoryCachePolicy Scoped(IRuntimeCacheProvider runtimeCache, IScope scope) - { - return new ScopedRepositoryCachePolicy(this, runtimeCache, scope); - } - protected static readonly TId[] EmptyIds = new TId[0]; // const protected string GetEntityTypeCacheKey() @@ -56,13 +51,15 @@ namespace Umbraco.Core.Cache // set to ListCloneBehavior.CloneOnce ie it will clone *once* when inserting, // and then will *not* clone when retrieving. + var key = GetEntityTypeCacheKey(); + if (_expires) { - Cache.InsertCacheItem(GetEntityTypeCacheKey(), () => new DeepCloneableList(entities), TimeSpan.FromMinutes(5), true); + Cache.InsertCacheItem(key, () => new DeepCloneableList(entities), TimeSpan.FromMinutes(5), true); } else { - Cache.InsertCacheItem(GetEntityTypeCacheKey(), () => new DeepCloneableList(entities)); + Cache.InsertCacheItem(key, () => new DeepCloneableList(entities)); } } diff --git a/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs index d01ae736c4..09d13cefec 100644 --- a/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs +++ b/src/Umbraco.Core/Cache/IRepositoryCachePolicy.cs @@ -8,26 +8,6 @@ namespace Umbraco.Core.Cache internal interface IRepositoryCachePolicy where TEntity : class, IAggregateRoot { - // note: - // at the moment each repository instance creates its corresponding cache policy instance - // we could reduce allocations by using static cache policy instances but then we would need - // to modify all methods here to pass the repository and cache eg: - // - // TEntity Get(TRepository repository, IRuntimeCacheProvider cache, TId id); - // - // 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. - - /// - /// 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. /// diff --git a/src/Umbraco.Core/Cache/NoCacheRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/NoCacheRepositoryCachePolicy.cs index ad0f6998cc..a638a41ce3 100644 --- a/src/Umbraco.Core/Cache/NoCacheRepositoryCachePolicy.cs +++ b/src/Umbraco.Core/Cache/NoCacheRepositoryCachePolicy.cs @@ -9,8 +9,7 @@ namespace Umbraco.Core.Cache internal class NoCacheRepositoryCachePolicy : IRepositoryCachePolicy where TEntity : class, IAggregateRoot { - private NoCacheRepositoryCachePolicy() - { } + private NoCacheRepositoryCachePolicy() { } public static NoCacheRepositoryCachePolicy Instance { get; } = new NoCacheRepositoryCachePolicy(); diff --git a/src/Umbraco.Core/Cache/NullCacheProvider.cs b/src/Umbraco.Core/Cache/NullCacheProvider.cs index f35f0ea2d3..1228feb350 100644 --- a/src/Umbraco.Core/Cache/NullCacheProvider.cs +++ b/src/Umbraco.Core/Cache/NullCacheProvider.cs @@ -10,6 +10,10 @@ namespace Umbraco.Core.Cache /// public class NullCacheProvider : IRuntimeCacheProvider { + private NullCacheProvider() { } + + public static NullCacheProvider Instance { get; } = new NullCacheProvider(); + public virtual void ClearAllCache() { } diff --git a/src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs b/src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs index a2febba029..e38dc0ac6b 100644 --- a/src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs +++ b/src/Umbraco.Core/Cache/RepositoryCachePolicyBase.cs @@ -13,14 +13,33 @@ namespace Umbraco.Core.Cache internal abstract class RepositoryCachePolicyBase : IRepositoryCachePolicy where TEntity : class, IAggregateRoot { - protected RepositoryCachePolicyBase(IRuntimeCacheProvider cache) + private readonly IRuntimeCacheProvider _globalCache; + private readonly IScopeAccessor _scopeAccessor; + + protected RepositoryCachePolicyBase(IRuntimeCacheProvider globalCache, IScopeAccessor scopeAccessor) { - Cache = cache ?? throw new ArgumentNullException(nameof(cache)); + _globalCache = globalCache ?? throw new ArgumentNullException(nameof(globalCache)); + _scopeAccessor = scopeAccessor ?? throw new ArgumentNullException(nameof(scopeAccessor)); } - public abstract IRepositoryCachePolicy Scoped(IRuntimeCacheProvider runtimeCache, IScope scope); - - protected IRuntimeCacheProvider Cache { get; } + protected IRuntimeCacheProvider Cache + { + get + { + var ambientScope = _scopeAccessor.AmbientScope; + switch (ambientScope.RepositoryCacheMode) + { + case RepositoryCacheMode.Default: + return _globalCache; + case RepositoryCacheMode.Scoped: + return ambientScope.IsolatedRuntimeCache.GetOrCreateCache(); + case RepositoryCacheMode.None: + return NullCacheProvider.Instance; + default: + throw new NotSupportedException($"Repository cache mode {ambientScope.RepositoryCacheMode} is not supported."); + } + } + } /// public abstract TEntity Get(TId id, Func performGet, Func> performGetAll); diff --git a/src/Umbraco.Core/Cache/ScopedRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/ScopedRepositoryCachePolicy.cs deleted file mode 100644 index f4244a49a1..0000000000 --- a/src/Umbraco.Core/Cache/ScopedRepositoryCachePolicy.cs +++ /dev/null @@ -1,75 +0,0 @@ -using System; -using System.Collections.Generic; -using Umbraco.Core.Models.EntityBase; -using Umbraco.Core.Scoping; - -namespace Umbraco.Core.Cache -{ - internal class ScopedRepositoryCachePolicy : IRepositoryCachePolicy - where TEntity : class, IAggregateRoot - { - private readonly IRepositoryCachePolicy _cachePolicy; - private readonly IRuntimeCacheProvider _globalIsolatedCache; - private readonly IScope _scope; - - public ScopedRepositoryCachePolicy(IRepositoryCachePolicy cachePolicy, IRuntimeCacheProvider globalIsolatedCache, IScope scope) - { - _cachePolicy = cachePolicy; - _globalIsolatedCache = globalIsolatedCache; - _scope = scope; - } - - public IRepositoryCachePolicy Scoped(IRuntimeCacheProvider runtimeCache, IScope scope) - { - throw new InvalidOperationException(); // obviously - } - - public TEntity Get(TId id, Func performGet, Func> performGetAll) - { - // loads into the local cache only, ok for now - return _cachePolicy.Get(id, performGet, performGetAll); - } - - public TEntity GetCached(TId id) - { - // loads into the local cache only, ok for now - return _cachePolicy.GetCached(id); - } - - public bool Exists(TId id, Func performExists, Func> performGetAll) - { - // loads into the local cache only, ok for now - return _cachePolicy.Exists(id, performExists, performGetAll); - } - - public void Create(TEntity entity, Action persistNew) - { - // writes into the local cache - _cachePolicy.Create(entity, persistNew); - } - - public void Update(TEntity entity, Action persistUpdated) - { - // writes into the local cache - _cachePolicy.Update(entity, persistUpdated); - } - - public void Delete(TEntity entity, Action persistDeleted) - { - // deletes the local cache - _cachePolicy.Delete(entity, persistDeleted); - } - - public TEntity[] GetAll(TId[] ids, Func> performGetAll) - { - // loads into the local cache only, ok for now - return _cachePolicy.GetAll(ids, performGetAll); - } - - public void ClearAll() - { - // clears the local cache - _cachePolicy.ClearAll(); - } - } -} diff --git a/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs b/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs index 76fe71b953..9ffcbd2b71 100644 --- a/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs +++ b/src/Umbraco.Core/Cache/SingleItemsOnlyRepositoryCachePolicy.cs @@ -1,4 +1,5 @@ using Umbraco.Core.Models.EntityBase; +using Umbraco.Core.Scoping; namespace Umbraco.Core.Cache { @@ -15,8 +16,8 @@ namespace Umbraco.Core.Cache internal class SingleItemsOnlyRepositoryCachePolicy : DefaultRepositoryCachePolicy where TEntity : class, IAggregateRoot { - public SingleItemsOnlyRepositoryCachePolicy(IRuntimeCacheProvider cache, RepositoryCachePolicyOptions options) - : base(cache, options) + public SingleItemsOnlyRepositoryCachePolicy(IRuntimeCacheProvider cache, IScopeAccessor scopeAccessor, RepositoryCachePolicyOptions options) + : base(cache, scopeAccessor, options) { } protected override void InsertEntities(TId[] ids, TEntity[] entities) diff --git a/src/Umbraco.Core/CoreRuntime.cs b/src/Umbraco.Core/CoreRuntime.cs index 57ec469757..8ab6d0ff76 100644 --- a/src/Umbraco.Core/CoreRuntime.cs +++ b/src/Umbraco.Core/CoreRuntime.cs @@ -194,7 +194,7 @@ namespace Umbraco.Core container.RegisterSingleton(_ => new CacheHelper( new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider()), new StaticCacheProvider(), - new NullCacheProvider(), + NullCacheProvider.Instance, new IsolatedRuntimeCache(type => new DeepCloneRuntimeCacheProvider(new ObjectCacheRuntimeCacheProvider())))); container.RegisterSingleton(f => f.GetInstance().RuntimeCache); diff --git a/src/Umbraco.Core/Models/Property.cs b/src/Umbraco.Core/Models/Property.cs index b8ef97d092..d90084f60b 100644 --- a/src/Umbraco.Core/Models/Property.cs +++ b/src/Umbraco.Core/Models/Property.cs @@ -57,7 +57,7 @@ namespace Umbraco.Core.Models public CompositeKey(int? key1, string key2) { _key1 = key1 ?? -1; - _key2 = key2; + _key2 = key2?.ToLowerInvariant() ?? "NEUTRAL"; } public bool Equals(CompositeKey other) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepository.cs index ba28d0e0d6..a546a15c84 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ContentTypeRepository.cs @@ -28,9 +28,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement protected override bool IsPublishing => ContentType.IsPublishingConst; - protected override IRepositoryCachePolicy CreateCachePolicy(IRuntimeCacheProvider runtimeCache) + protected override IRepositoryCachePolicy CreateCachePolicy() { - return new FullDataSetRepositoryCachePolicy(runtimeCache, GetEntityId, /*expires:*/ true); + return new FullDataSetRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ true); } protected override IContentType PerformGet(int id) @@ -201,9 +201,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement var children = Get(query); foreach (var child in children) { - //NOTE: We must cast here so that it goes to the outter method to - // ensure the cache is updated. - PersistDeletedItem((IEntity)child); + PersistDeletedItem(child); } //Before we call the base class methods to run all delete clauses, we need to first diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs index 87e435a5e8..128ccb9155 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DictionaryRepository.cs @@ -22,7 +22,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement : base(scopeAccessor, cache, logger) { } - protected override IRepositoryCachePolicy CreateCachePolicy(IRuntimeCacheProvider runtimeCache) + protected override IRepositoryCachePolicy CreateCachePolicy() { var options = new RepositoryCachePolicyOptions { @@ -30,7 +30,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement GetAllCacheAllowZeroCount = true }; - return new SingleItemsOnlyRepositoryCachePolicy(runtimeCache, options); + return new SingleItemsOnlyRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, options); } #region Overrides of RepositoryBase @@ -333,7 +333,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement return "cmsDictionary." + SqlSyntax.GetQuotedColumnName("id") + " in (@ids)"; } - protected override IRepositoryCachePolicy CreateCachePolicy(IRuntimeCacheProvider runtimeCache) + protected override IRepositoryCachePolicy CreateCachePolicy() { var options = new RepositoryCachePolicyOptions { @@ -341,7 +341,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement GetAllCacheAllowZeroCount = true }; - return new SingleItemsOnlyRepositoryCachePolicy(runtimeCache, options); + return new SingleItemsOnlyRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, options); } } @@ -386,7 +386,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement return "cmsDictionary." + SqlSyntax.GetQuotedColumnName("key") + " in (@ids)"; } - protected override IRepositoryCachePolicy CreateCachePolicy(IRuntimeCacheProvider runtimeCache) + protected override IRepositoryCachePolicy CreateCachePolicy() { var options = new RepositoryCachePolicyOptions { @@ -394,7 +394,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement GetAllCacheAllowZeroCount = true }; - return new SingleItemsOnlyRepositoryCachePolicy(runtimeCache, options); + return new SingleItemsOnlyRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, options); } } } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs index 4892a9d0d7..76316957b2 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DocumentRepository.cs @@ -7,6 +7,7 @@ using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Exceptions; using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Models.Membership; using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence.DatabaseModelDefinitions; diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/DomainRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/DomainRepository.cs index 24667cd8b9..ff999acf04 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/DomainRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/DomainRepository.cs @@ -20,9 +20,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement : base(scopeAccessor, cache, logger) { } - protected override IRepositoryCachePolicy CreateCachePolicy(IRuntimeCacheProvider runtimeCache) + protected override IRepositoryCachePolicy CreateCachePolicy() { - return new FullDataSetRepositoryCachePolicy(runtimeCache, GetEntityId, /*expires:*/ false); + return new FullDataSetRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ false); } protected override IDomain PerformGet(int id) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityContainerRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityContainerRepository.cs index 569e3310a1..6b1a3275f3 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/EntityContainerRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/EntityContainerRepository.cs @@ -6,6 +6,7 @@ using Umbraco.Core.Cache; using Umbraco.Core.Exceptions; using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence.Querying; using Umbraco.Core.Scoping; @@ -29,10 +30,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement } // never cache - private static readonly IRuntimeCacheProvider NullCache = new NullCacheProvider(); - protected override IRuntimeCacheProvider GetIsolatedCache(IsolatedRuntimeCache provider) + protected override IRepositoryCachePolicy CreateCachePolicy() { - return NullCache; + return NoCacheRepositoryCachePolicy.Instance; } protected override EntityContainer PerformGet(int id) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs index 9bd2f175a9..b420fa8bf5 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/LanguageRepository.cs @@ -22,9 +22,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement : base(scopeAccessor, cache, logger) { } - protected override IRepositoryCachePolicy CreateCachePolicy(IRuntimeCacheProvider runtimeCache) + protected override IRepositoryCachePolicy CreateCachePolicy() { - return new FullDataSetRepositoryCachePolicy(runtimeCache, GetEntityId, /*expires:*/ false); + return new FullDataSetRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ false); } #region Overrides of RepositoryBase diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MediaRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MediaRepository.cs index 6e8b77fd5c..acad4c68fe 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/MediaRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MediaRepository.cs @@ -8,6 +8,7 @@ using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Exceptions; using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.Factories; diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MediaTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MediaTypeRepository.cs index 12cb6010fd..b473e9aef9 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/MediaTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MediaTypeRepository.cs @@ -22,9 +22,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement protected override bool IsPublishing => MediaType.IsPublishingConst; - protected override IRepositoryCachePolicy CreateCachePolicy(IRuntimeCacheProvider runtimeCache) + protected override IRepositoryCachePolicy CreateCachePolicy() { - return new FullDataSetRepositoryCachePolicy(runtimeCache, GetEntityId, /*expires:*/ true); + return new FullDataSetRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ true); } protected override IMediaType PerformGet(int id) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs index d3a4d58c0d..551ce76945 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberRepository.cs @@ -6,6 +6,7 @@ using NPoco; using Umbraco.Core.Cache; using Umbraco.Core.Logging; using Umbraco.Core.Models; +using Umbraco.Core.Models.EntityBase; using Umbraco.Core.Models.Rdbms; using Umbraco.Core.Persistence.DatabaseModelDefinitions; using Umbraco.Core.Persistence.Factories; diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberTypeRepository.cs index 16d1843952..64021d2316 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/MemberTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/MemberTypeRepository.cs @@ -23,9 +23,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement protected override bool IsPublishing => MemberType.IsPublishingConst; - protected override IRepositoryCachePolicy CreateCachePolicy(IRuntimeCacheProvider runtimeCache) + protected override IRepositoryCachePolicy CreateCachePolicy() { - return new FullDataSetRepositoryCachePolicy(runtimeCache, GetEntityId, /*expires:*/ true); + return new FullDataSetRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ true); } protected override IMemberType PerformGet(int id) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/PublicAccessRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/PublicAccessRepository.cs index dc0e93733b..7381b6ddd8 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/PublicAccessRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/PublicAccessRepository.cs @@ -18,9 +18,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement : base(scopeAccessor, cache, logger) { } - protected override IRepositoryCachePolicy CreateCachePolicy(IRuntimeCacheProvider runtimeCache) + protected override IRepositoryCachePolicy CreateCachePolicy() { - return new FullDataSetRepositoryCachePolicy(runtimeCache, GetEntityId, /*expires:*/ false); + return new FullDataSetRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ false); } protected override PublicAccessEntry PerformGet(Guid id) diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/RelationTypeRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/RelationTypeRepository.cs index 8fe3e3819a..9ed98c023f 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/RelationTypeRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/RelationTypeRepository.cs @@ -22,9 +22,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement : base(scopeAccessor, cache, logger) { } - protected override IRepositoryCachePolicy CreateCachePolicy(IRuntimeCacheProvider runtimeCache) + protected override IRepositoryCachePolicy CreateCachePolicy() { - return new FullDataSetRepositoryCachePolicy(runtimeCache, GetEntityId, /*expires:*/ true); + return new FullDataSetRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ true); } #region Overrides of RepositoryBase diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs index e5bdd99ec4..b9e9dc182a 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/RepositoryBaseOfTIdTEntity.cs @@ -18,7 +18,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement where TEntity : class, IAggregateRoot { private IRepositoryCachePolicy _cachePolicy; - private IRuntimeCacheProvider _isolatedCache; protected RepositoryBase(IScopeAccessor scopeAccessor, CacheHelper cache, ILogger logger) { @@ -31,6 +30,8 @@ namespace Umbraco.Core.Persistence.Repositories.Implement protected CacheHelper GlobalCache { get; } + protected IRuntimeCacheProvider GlobalIsolatedCache => GlobalCache.IsolatedRuntimeCache.GetOrCreateCache(); + protected IScopeAccessor ScopeAccessor { get; } protected IScope AmbientScope @@ -56,38 +57,28 @@ namespace Umbraco.Core.Persistence.Repositories.Implement } /// - /// The runtime cache used for this repo by default is the isolated cache for this type + /// Gets the isolated cache. /// + /// Depends on the ambient scope cache mode. protected IRuntimeCacheProvider IsolatedCache { get { - if (_isolatedCache != null) return _isolatedCache; - - IsolatedRuntimeCache provider; switch (AmbientScope.RepositoryCacheMode) { case RepositoryCacheMode.Default: - provider = GlobalCache.IsolatedRuntimeCache; - break; + return GlobalCache.IsolatedRuntimeCache.GetOrCreateCache(); case RepositoryCacheMode.Scoped: - provider = AmbientScope.IsolatedRuntimeCache; - break; + return AmbientScope.IsolatedRuntimeCache.GetOrCreateCache(); case RepositoryCacheMode.None: - return new NullCacheProvider(); // fixme cache instance + return NullCacheProvider.Instance; default: throw new Exception("oops: cache mode."); } - - return _isolatedCache = GetIsolatedCache(provider); } } - protected virtual IRuntimeCacheProvider GetIsolatedCache(IsolatedRuntimeCache provider) - { - return provider.GetOrCreateCache(); - } - + // fixme - but now that we have 1 unique repository? // this is a *bad* idea because PerformCount captures the current repository and its UOW // //private static RepositoryCachePolicyOptions _defaultOptions; @@ -132,39 +123,35 @@ namespace Umbraco.Core.Persistence.Repositories.Implement // } //} - protected virtual IRepositoryCachePolicy CachePolicy + protected IRepositoryCachePolicy CachePolicy { get { if (GlobalCache == CacheHelper.NoCache) - return _cachePolicy = NoCacheRepositoryCachePolicy.Instance; + return NoCacheRepositoryCachePolicy.Instance; // create the cache policy using IsolatedCache which is either global // or scoped depending on the repository cache mode for the current scope + switch (AmbientScope.RepositoryCacheMode) { case RepositoryCacheMode.Default: - _cachePolicy = CreateCachePolicy(IsolatedCache); - break; case RepositoryCacheMode.Scoped: - _cachePolicy = CreateCachePolicy(IsolatedCache); - var globalIsolatedCache = GetIsolatedCache(GlobalCache.IsolatedRuntimeCache); - _cachePolicy = _cachePolicy.Scoped(globalIsolatedCache, AmbientScope); - break; + // return the same cache policy in both cases - the cache policy is + // supposed to pick either the global or scope cache depending on the + // scope cache mode + return _cachePolicy ?? (_cachePolicy = CreateCachePolicy()); case RepositoryCacheMode.None: - _cachePolicy = NoCacheRepositoryCachePolicy.Instance; - break; + return NoCacheRepositoryCachePolicy.Instance; default: throw new Exception("oops: cache mode."); } - - return _cachePolicy; } } - protected virtual IRepositoryCachePolicy CreateCachePolicy(IRuntimeCacheProvider runtimeCache) + protected virtual IRepositoryCachePolicy CreateCachePolicy() { - return new DefaultRepositoryCachePolicy(runtimeCache, DefaultOptions); + return new DefaultRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, DefaultOptions); } /// @@ -175,9 +162,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement public void Save(TEntity entity) { if (entity.HasIdentity == false) - PersistNewItem(entity); + CachePolicy.Create(entity, PersistNewItem); else - PersistUpdatedItem(entity); + CachePolicy.Update(entity, PersistUpdatedItem); } /// @@ -186,7 +173,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement /// public virtual void Delete(TEntity entity) { - PersistDeletedItem(entity); + CachePolicy.Delete(entity, PersistDeletedItem); } protected abstract TEntity PerformGet(TId id); @@ -194,6 +181,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement protected abstract IEnumerable PerformGetByQuery(IQuery query); protected abstract bool PerformExists(TId id); protected abstract int PerformCount(IQuery query); + protected abstract void PersistNewItem(TEntity item); protected abstract void PersistUpdatedItem(TEntity item); protected abstract void PersistDeletedItem(TEntity item); @@ -262,32 +250,5 @@ namespace Umbraco.Core.Persistence.Repositories.Implement { return PerformCount(query); } - - /// - /// Unit of work method that tells the repository to persist the new entity - /// - /// - public virtual void PersistNewItem(IEntity entity) - { - CachePolicy.Create((TEntity) entity, PersistNewItem); - } - - /// - /// Unit of work method that tells the repository to persist the updated entity - /// - /// - public virtual void PersistUpdatedItem(IEntity entity) - { - CachePolicy.Update((TEntity) entity, PersistUpdatedItem); - } - - /// - /// Unit of work method that tells the repository to persist the deletion of the entity - /// - /// - public virtual void PersistDeletedItem(IEntity entity) - { - CachePolicy.Delete((TEntity) entity, PersistDeletedItem); - } } } diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/ServerRegistrationRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/ServerRegistrationRepository.cs index a32b756429..aea799f606 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/ServerRegistrationRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/ServerRegistrationRepository.cs @@ -19,7 +19,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement : base(scopeAccessor, CacheHelper.CreateDisabledCacheHelper(), logger) { } - protected override IRepositoryCachePolicy CreateCachePolicy(IRuntimeCacheProvider runtimeCache) + protected override IRepositoryCachePolicy CreateCachePolicy() { // fixme - wtf are we doing with cache here? // why are we using disabled cache helper up there? @@ -29,7 +29,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement // and this is because the repository is special and should not participate in scopes // (cleanup in v8) // - return new FullDataSetRepositoryCachePolicy(GlobalCache.RuntimeCache, GetEntityId, /*expires:*/ false); + return new FullDataSetRepositoryCachePolicy(GlobalCache.RuntimeCache, ScopeAccessor, GetEntityId, /*expires:*/ false); } public void ClearCache() diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/TemplateRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/TemplateRepository.cs index acfcd903e2..a4699c7b34 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/TemplateRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/TemplateRepository.cs @@ -42,9 +42,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement _masterPageHelper = new MasterPageHelper(_masterpagesFileSystem); } - protected override IRepositoryCachePolicy CreateCachePolicy(IRuntimeCacheProvider runtimeCache) + protected override IRepositoryCachePolicy CreateCachePolicy() { - return new FullDataSetRepositoryCachePolicy(runtimeCache, GetEntityId, /*expires:*/ false); + return new FullDataSetRepositoryCachePolicy(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ false); } #region Overrides of RepositoryBase diff --git a/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs b/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs index 9d076bdb94..4f7bdca0cf 100644 --- a/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs +++ b/src/Umbraco.Core/Persistence/Repositories/Implement/UserRepository.cs @@ -60,6 +60,10 @@ namespace Umbraco.Core.Persistence.Repositories.Implement if (_passwordConfigInitialized) return _passwordConfigJson; + // fixme - this is bad + // because the membership provider we're trying to get has a dependency on the user service + // and we should not depend on services in repositories - need a way better way to do this + var userMembershipProvider = MembershipProviderExtensions.GetUsersMembershipProvider(); var passwordConfig = userMembershipProvider == null || userMembershipProvider.PasswordFormat != MembershipPasswordFormat.Hashed ? null diff --git a/src/Umbraco.Core/Scoping/IScopeProvider.cs b/src/Umbraco.Core/Scoping/IScopeProvider.cs index c5e11dd020..6c9eb63ba0 100644 --- a/src/Umbraco.Core/Scoping/IScopeProvider.cs +++ b/src/Umbraco.Core/Scoping/IScopeProvider.cs @@ -22,12 +22,15 @@ namespace Umbraco.Core.Scoping /// An optional events dispatcher. /// A value indicating whether to scope the filesystems. /// A value indicating whether this scope should always be registered in the call context. + /// A value indicating whether this scope is auto-completed. /// The created ambient scope. /// /// The created scope becomes the ambient scope. /// If an ambient scope already exists, it becomes the parent of the created scope. /// When the created scope is disposed, the parent scope becomes the ambient scope again. /// Parameters must be specified on the outermost scope, or must be compatible with the parents. + /// Auto-completed scopes should be used for read-only operations ONLY. Do not use them if you do not + /// understand the associated issues, such as the scope being completed even though an exception is thrown. /// IScope CreateScope( IsolationLevel isolationLevel = IsolationLevel.Unspecified, @@ -35,7 +38,7 @@ namespace Umbraco.Core.Scoping IEventDispatcher eventDispatcher = null, bool? scopeFileSystems = null, bool callContext = false, - bool readOnly = false); // fixme rename to autoComplete + explain the risks! + bool autoComplete = false); /// /// Creates a detached scope. diff --git a/src/Umbraco.Core/Scoping/Scope.cs b/src/Umbraco.Core/Scoping/Scope.cs index ccdec6fe45..431e5aaa2b 100644 --- a/src/Umbraco.Core/Scoping/Scope.cs +++ b/src/Umbraco.Core/Scoping/Scope.cs @@ -28,6 +28,7 @@ namespace Umbraco.Core.Scoping private readonly RepositoryCacheMode _repositoryCacheMode; private readonly bool? _scopeFileSystem; private readonly ScopeContext _scopeContext; + private readonly bool _autoComplete; private bool _callContext; private bool _disposed; @@ -48,7 +49,8 @@ namespace Umbraco.Core.Scoping RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified, IEventDispatcher eventDispatcher = null, bool? scopeFileSystems = null, - bool callContext = false) + bool callContext = false, + bool autoComplete = false) { _scopeProvider = scopeProvider; _logger = logger; @@ -60,6 +62,7 @@ namespace Umbraco.Core.Scoping _eventDispatcher = eventDispatcher; _scopeFileSystem = scopeFileSystems; _callContext = callContext; + _autoComplete = autoComplete; Detachable = detachable; @@ -72,6 +75,7 @@ namespace Umbraco.Core.Scoping { if (parent != null) throw new ArgumentException("Cannot set parent on detachable scope.", nameof(parent)); if (scopeContext != null) throw new ArgumentException("Cannot set context on detachable scope.", nameof(scopeContext)); + if (autoComplete) throw new ArgumentException("Cannot auto-complete a detachable scope.", nameof(autoComplete)); // detachable creates its own scope context _scopeContext = new ScopeContext(); @@ -119,8 +123,9 @@ namespace Umbraco.Core.Scoping RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified, IEventDispatcher eventDispatcher = null, bool? scopeFileSystems = null, - bool callContext = false) - : this(scopeProvider, logger, fileSystems, null, scopeContext, detachable, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext) + bool callContext = false, + bool autoComplete = false) + : this(scopeProvider, logger, fileSystems, null, scopeContext, detachable, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete) { } // initializes a new scope in a nested scopes chain, with its parent @@ -130,8 +135,9 @@ namespace Umbraco.Core.Scoping RepositoryCacheMode repositoryCacheMode = RepositoryCacheMode.Unspecified, IEventDispatcher eventDispatcher = null, bool? scopeFileSystems = null, - bool callContext = false) - : this(scopeProvider, logger, fileSystems, parent, null, false, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext) + bool callContext = false, + bool autoComplete = false) + : this(scopeProvider, logger, fileSystems, parent, null, false, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete) { } public Guid InstanceId { get; } = Guid.NewGuid(); @@ -356,6 +362,9 @@ namespace Umbraco.Core.Scoping _scopeProvider.Disposed(this); #endif + if (_autoComplete && _completed == null) + _completed = true; + if (parent != null) parent.ChildCompleted(_completed); else @@ -414,7 +423,7 @@ namespace Umbraco.Core.Scoping // to ensure we don't leave a scope around, etc private void RobustExit(bool completed, bool onException) { - if (onException) completed = false; + if (onException) completed = false; TryFinally(() => { diff --git a/src/Umbraco.Core/Scoping/ScopeProvider.cs b/src/Umbraco.Core/Scoping/ScopeProvider.cs index 555d943714..6dd294eb1a 100644 --- a/src/Umbraco.Core/Scoping/ScopeProvider.cs +++ b/src/Umbraco.Core/Scoping/ScopeProvider.cs @@ -375,14 +375,14 @@ namespace Umbraco.Core.Scoping IEventDispatcher eventDispatcher = null, bool? scopeFileSystems = null, bool callContext = false, - bool readOnly = false) // fixme + bool autoComplete = false) { var ambient = AmbientScope; if (ambient == null) { var ambientContext = AmbientContext; var newContext = ambientContext == null ? new ScopeContext() : null; - var scope = new Scope(this, _logger, _fileSystems, false, newContext, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext); + var scope = new Scope(this, _logger, _fileSystems, false, newContext, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete); // assign only if scope creation did not throw! SetAmbient(scope, newContext ?? ambientContext); return scope; @@ -391,7 +391,7 @@ namespace Umbraco.Core.Scoping var ambientScope = ambient as Scope; if (ambientScope == null) throw new Exception("Ambient scope is not a Scope instance."); // fixme - why? how? - var nested = new Scope(this, _logger, _fileSystems, ambientScope, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext); + var nested = new Scope(this, _logger, _fileSystems, ambientScope, isolationLevel, repositoryCacheMode, eventDispatcher, scopeFileSystems, callContext, autoComplete); SetAmbient(nested, AmbientContext); return nested; } diff --git a/src/Umbraco.Core/Services/ContentService.cs b/src/Umbraco.Core/Services/ContentService.cs index a266ecdc97..405687cf68 100644 --- a/src/Umbraco.Core/Services/ContentService.cs +++ b/src/Umbraco.Core/Services/ContentService.cs @@ -60,7 +60,7 @@ namespace Umbraco.Core.Services public int CountPublished(string contentTypeAlias = null) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); return _documentRepository.CountPublished(); @@ -69,7 +69,7 @@ namespace Umbraco.Core.Services public int Count(string contentTypeAlias = null) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); return _documentRepository.Count(contentTypeAlias); @@ -78,7 +78,7 @@ namespace Umbraco.Core.Services public int CountChildren(int parentId, string contentTypeAlias = null) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); return _documentRepository.CountChildren(parentId, contentTypeAlias); @@ -87,7 +87,7 @@ namespace Umbraco.Core.Services public int CountDescendants(int parentId, string contentTypeAlias = null) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); return _documentRepository.CountDescendants(parentId, contentTypeAlias); @@ -136,7 +136,7 @@ namespace Umbraco.Core.Services /// public EntityPermissionCollection GetPermissions(IContent content) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); return _documentRepository.GetPermissionsForEntity(content.Id); @@ -373,7 +373,7 @@ namespace Umbraco.Core.Services /// public IContent GetById(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); return _documentRepository.Get(id); @@ -390,7 +390,7 @@ namespace Umbraco.Core.Services var idsA = ids.ToArray(); if (idsA.Length == 0) return Enumerable.Empty(); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); var items = _documentRepository.GetMany(idsA); @@ -408,7 +408,7 @@ namespace Umbraco.Core.Services /// public IContent GetById(Guid key) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); return _documentRepository.Get(key); @@ -425,7 +425,7 @@ namespace Umbraco.Core.Services var idsA = ids.ToArray(); if (idsA.Length == 0) return Enumerable.Empty(); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); var items = _documentRepository.GetMany(idsA); @@ -443,7 +443,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetByType(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); var query = Query().Where(x => x.ContentTypeId == id); @@ -453,7 +453,7 @@ namespace Umbraco.Core.Services internal IEnumerable GetPublishedContentOfContentType(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); var query = Query().Where(x => x.ContentTypeId == id); @@ -469,7 +469,7 @@ namespace Umbraco.Core.Services /// Contrary to most methods, this method filters out trashed content items. public IEnumerable GetByLevel(int level) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); var query = Query().Where(x => x.Level == level && x.Trashed == false); @@ -484,7 +484,7 @@ namespace Umbraco.Core.Services /// An item public IContent GetVersion(int versionId) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); return _documentRepository.GetVersion(versionId); @@ -498,7 +498,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetVersions(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); return _documentRepository.GetAllVersions(id); @@ -513,7 +513,7 @@ namespace Umbraco.Core.Services /// public IEnumerable GetVersionIds(int id, int maxRows) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _documentRepository.GetVersionIds(id, maxRows); } @@ -547,7 +547,7 @@ namespace Umbraco.Core.Services if (ids.Any() == false) return new List(); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); return _documentRepository.GetMany(ids); @@ -561,7 +561,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetChildren(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); var query = Query().Where(x => x.ParentId == id); @@ -576,7 +576,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of published objects public IEnumerable GetPublishedChildren(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); var query = Query().Where(x => x.ParentId == id && x.Published); @@ -598,7 +598,7 @@ namespace Umbraco.Core.Services public IEnumerable GetPagedChildren(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy, Direction orderDirection, string filter = "") { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); var filterQuery = filter.IsNullOrWhiteSpace() @@ -627,7 +627,7 @@ namespace Umbraco.Core.Services if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex)); if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize)); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); @@ -652,7 +652,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetPagedDescendants(int id, long pageIndex, int pageSize, out long totalChildren, string orderBy = "Path", Direction orderDirection = Direction.Ascending, string filter = "") { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); var filterQuery = filter.IsNullOrWhiteSpace() @@ -680,7 +680,7 @@ namespace Umbraco.Core.Services if (pageIndex < 0) throw new ArgumentOutOfRangeException(nameof(pageIndex)); if (pageSize <= 0) throw new ArgumentOutOfRangeException(nameof(pageSize)); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); @@ -708,7 +708,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetChildren(int parentId, string name) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); var query = Query().Where(x => x.ParentId == parentId && x.Name.Contains(name)); @@ -723,7 +723,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetDescendants(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); var content = GetById(id); @@ -745,7 +745,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetDescendants(IContent content) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); var pathMatch = content.Path + ","; @@ -785,7 +785,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetRootContent() { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); var query = Query().Where(x => x.ParentId == Constants.System.Root); @@ -799,7 +799,7 @@ namespace Umbraco.Core.Services /// internal IEnumerable GetAllPublished() { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); return _documentRepository.Get(QueryNotTrashed); @@ -812,7 +812,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetContentForExpiration() { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); var query = Query().Where(x => x.Published && x.ExpireDate <= DateTime.Now); @@ -826,7 +826,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetContentForRelease() { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); var query = Query().Where(x => x.Published == false && x.ReleaseDate <= DateTime.Now); @@ -840,7 +840,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects public IEnumerable GetContentInRecycleBin() { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); var bin = $"{Constants.System.Root},{Constants.System.RecycleBinContent},"; @@ -877,7 +877,7 @@ namespace Umbraco.Core.Services public bool IsPathPublished(IContent content) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); return _documentRepository.IsPathPublished(content); @@ -1019,6 +1019,10 @@ namespace Umbraco.Core.Services content.CreatorId = userId; content.WriterId = userId; + // if not going to publish, must reset the published state + if (!result.Success) + ((Content) content).Published = content.Published; + _documentRepository.Save(content); if (raiseEvents) // always @@ -1826,7 +1830,7 @@ namespace Umbraco.Core.Services /// An Enumerable list of objects internal IEnumerable GetPublishedDescendants(IContent content) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); return GetPublishedDescendantsLocked(content).ToArray(); // ToArray important in uow! @@ -2234,7 +2238,7 @@ namespace Umbraco.Core.Services { if (string.IsNullOrWhiteSpace(contentTypeAlias)) throw new ArgumentNullOrEmptyException(nameof(contentTypeAlias)); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return GetContentType(scope, contentTypeAlias); } @@ -2246,7 +2250,7 @@ namespace Umbraco.Core.Services public IContent GetBlueprintById(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); var blueprint = _documentBlueprintRepository.Get(id); @@ -2258,7 +2262,7 @@ namespace Umbraco.Core.Services public IContent GetBlueprintById(Guid id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(Constants.Locks.ContentTree); var blueprint = _documentBlueprintRepository.Get(id); @@ -2329,7 +2333,7 @@ namespace Umbraco.Core.Services public IEnumerable GetBlueprintsForContentTypes(params int[] contentTypeId) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var query = Query(); if (contentTypeId.Length > 0) diff --git a/src/Umbraco.Core/Services/ContentTypeService.cs b/src/Umbraco.Core/Services/ContentTypeService.cs index 94f207fc70..077b522064 100644 --- a/src/Umbraco.Core/Services/ContentTypeService.cs +++ b/src/Umbraco.Core/Services/ContentTypeService.cs @@ -44,7 +44,7 @@ namespace Umbraco.Core.Services /// Beware! Works accross content, media and member types. public IEnumerable GetAllPropertyTypeAliases() { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { // that one is special because it works accross content, media and member types scope.ReadLock(Constants.Locks.ContentTypes, Constants.Locks.MediaTypes, Constants.Locks.MemberTypes); @@ -60,7 +60,7 @@ namespace Umbraco.Core.Services /// Beware! Works accross content, media and member types. public IEnumerable GetAllContentTypeAliases(params Guid[] guids) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { // that one is special because it works accross content, media and member types scope.ReadLock(Constants.Locks.ContentTypes, Constants.Locks.MediaTypes, Constants.Locks.MemberTypes); @@ -76,7 +76,7 @@ namespace Umbraco.Core.Services /// Beware! Works accross content, media and member types. public IEnumerable GetAllContentTypeIds(string[] aliases) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { // that one is special because it works accross content, media and member types scope.ReadLock(Constants.Locks.ContentTypes, Constants.Locks.MediaTypes, Constants.Locks.MemberTypes); diff --git a/src/Umbraco.Core/Services/ContentTypeServiceBaseOfTRepositoryTItemTService.cs b/src/Umbraco.Core/Services/ContentTypeServiceBaseOfTRepositoryTItemTService.cs index a36f83b4e3..33f1b8a1df 100644 --- a/src/Umbraco.Core/Services/ContentTypeServiceBaseOfTRepositoryTItemTService.cs +++ b/src/Umbraco.Core/Services/ContentTypeServiceBaseOfTRepositoryTItemTService.cs @@ -42,7 +42,7 @@ namespace Umbraco.Core.Services { try { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(ReadLockIds); ValidateLocked(compo); @@ -203,7 +203,7 @@ namespace Umbraco.Core.Services public TItem Get(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(ReadLockIds); return Repository.Get(id); @@ -212,7 +212,7 @@ namespace Umbraco.Core.Services public TItem Get(string alias) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(ReadLockIds); return Repository.Get(alias); @@ -221,7 +221,7 @@ namespace Umbraco.Core.Services public TItem Get(Guid id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(ReadLockIds); return Repository.Get(id); @@ -230,7 +230,7 @@ namespace Umbraco.Core.Services public IEnumerable GetAll(params int[] ids) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(ReadLockIds); return Repository.GetMany(ids); @@ -239,7 +239,7 @@ namespace Umbraco.Core.Services public IEnumerable GetAll(params Guid[] ids) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(ReadLockIds); return Repository.GetMany(ids); @@ -248,7 +248,7 @@ namespace Umbraco.Core.Services public IEnumerable GetChildren(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(ReadLockIds); var query = Query().Where(x => x.ParentId == id); @@ -258,7 +258,7 @@ namespace Umbraco.Core.Services public IEnumerable GetChildren(Guid id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(ReadLockIds); var found = Get(id); @@ -270,7 +270,7 @@ namespace Umbraco.Core.Services public bool HasChildren(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(ReadLockIds); var query = Query().Where(x => x.ParentId == id); @@ -281,7 +281,7 @@ namespace Umbraco.Core.Services public bool HasChildren(Guid id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(ReadLockIds); var found = Get(id); @@ -299,7 +299,7 @@ namespace Umbraco.Core.Services /// public bool HasContainerInPath(string contentPath) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { // can use same repo for both content and media return Repository.HasContainerInPath(contentPath); @@ -308,7 +308,7 @@ namespace Umbraco.Core.Services public IEnumerable GetDescendants(int id, bool andSelf) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(ReadLockIds); @@ -336,7 +336,7 @@ namespace Umbraco.Core.Services public IEnumerable GetComposedOf(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(ReadLockIds); @@ -366,7 +366,7 @@ namespace Umbraco.Core.Services public int Count() { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(ReadLockIds); return Repository.Count(Query()); @@ -816,7 +816,7 @@ namespace Umbraco.Core.Services public EntityContainer GetContainer(int containerId) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(ReadLockIds); // also for containers @@ -826,7 +826,7 @@ namespace Umbraco.Core.Services public EntityContainer GetContainer(Guid containerId) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(ReadLockIds); // also for containers @@ -836,7 +836,7 @@ namespace Umbraco.Core.Services public IEnumerable GetContainers(int[] containerIds) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(ReadLockIds); // also for containers @@ -860,7 +860,7 @@ namespace Umbraco.Core.Services public IEnumerable GetContainers(string name, int level) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { scope.ReadLock(ReadLockIds); // also for containers diff --git a/src/Umbraco.Core/Services/DataTypeService.cs b/src/Umbraco.Core/Services/DataTypeService.cs index 644ce8ac40..68ac76286e 100644 --- a/src/Umbraco.Core/Services/DataTypeService.cs +++ b/src/Umbraco.Core/Services/DataTypeService.cs @@ -75,7 +75,7 @@ namespace Umbraco.Core.Services public EntityContainer GetContainer(int containerId) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _dataTypeContainerRepository.Get(containerId); } @@ -83,7 +83,7 @@ namespace Umbraco.Core.Services public EntityContainer GetContainer(Guid containerId) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return ((EntityContainerRepository) _dataTypeContainerRepository).Get(containerId); } @@ -91,7 +91,7 @@ namespace Umbraco.Core.Services public IEnumerable GetContainers(string name, int level) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return ((EntityContainerRepository) _dataTypeContainerRepository).Get(name, level); } @@ -113,7 +113,7 @@ namespace Umbraco.Core.Services public IEnumerable GetContainers(int[] containerIds) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _dataTypeContainerRepository.GetMany(containerIds); } @@ -220,7 +220,7 @@ namespace Umbraco.Core.Services /// public IDataTypeDefinition GetDataTypeDefinitionByName(string name) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _dataTypeDefinitionRepository.Get(Query().Where(x => x.Name == name)).FirstOrDefault(); } @@ -233,7 +233,7 @@ namespace Umbraco.Core.Services /// public IDataTypeDefinition GetDataTypeDefinitionById(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _dataTypeDefinitionRepository.Get(id); } @@ -246,7 +246,7 @@ namespace Umbraco.Core.Services /// public IDataTypeDefinition GetDataTypeDefinitionById(Guid id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var query = Query().Where(x => x.Key == id); return _dataTypeDefinitionRepository.Get(query).FirstOrDefault(); @@ -260,7 +260,7 @@ namespace Umbraco.Core.Services /// Collection of objects with a matching contorl id public IEnumerable GetDataTypeDefinitionByPropertyEditorAlias(string propertyEditorAlias) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var query = Query().Where(x => x.PropertyEditorAlias == propertyEditorAlias); return _dataTypeDefinitionRepository.Get(query); @@ -274,7 +274,7 @@ namespace Umbraco.Core.Services /// An enumerable list of objects public IEnumerable GetAllDataTypeDefinitions(params int[] ids) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _dataTypeDefinitionRepository.GetMany(ids); } @@ -287,7 +287,7 @@ namespace Umbraco.Core.Services /// An enumerable list of string values public IEnumerable GetPreValuesByDataTypeId(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var collection = _dataTypeDefinitionRepository.GetPreValuesCollectionByDataTypeId(id); //now convert the collection to a string list @@ -304,7 +304,7 @@ namespace Umbraco.Core.Services /// public PreValueCollection GetPreValuesCollectionByDataTypeId(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _dataTypeDefinitionRepository.GetPreValuesCollectionByDataTypeId(id); } @@ -317,7 +317,7 @@ namespace Umbraco.Core.Services /// PreValue as a string public string GetPreValueAsString(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _dataTypeDefinitionRepository.GetPreValueAsString(id); } diff --git a/src/Umbraco.Core/Services/DomainService.cs b/src/Umbraco.Core/Services/DomainService.cs index a7e1cf22f6..2688b6b452 100644 --- a/src/Umbraco.Core/Services/DomainService.cs +++ b/src/Umbraco.Core/Services/DomainService.cs @@ -20,7 +20,7 @@ namespace Umbraco.Core.Services public bool Exists(string domainName) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _domainRepository.Exists(domainName); } @@ -51,7 +51,7 @@ namespace Umbraco.Core.Services public IDomain GetByName(string name) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _domainRepository.GetByName(name); } @@ -59,7 +59,7 @@ namespace Umbraco.Core.Services public IDomain GetById(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _domainRepository.Get(id); } @@ -67,7 +67,7 @@ namespace Umbraco.Core.Services public IEnumerable GetAll(bool includeWildcards) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _domainRepository.GetAll(includeWildcards); } @@ -75,7 +75,7 @@ namespace Umbraco.Core.Services public IEnumerable GetAssignedDomains(int contentId, bool includeWildcards) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _domainRepository.GetAssignedDomains(contentId, includeWildcards); } diff --git a/src/Umbraco.Core/Services/EntityService.cs b/src/Umbraco.Core/Services/EntityService.cs index 5aa6340d3e..260546e9b6 100644 --- a/src/Umbraco.Core/Services/EntityService.cs +++ b/src/Umbraco.Core/Services/EntityService.cs @@ -90,7 +90,7 @@ namespace Umbraco.Core.Services { if (loadBaseType) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _entityRepository.GetByKey(key); } @@ -120,7 +120,7 @@ namespace Umbraco.Core.Services { if (loadBaseType) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _entityRepository.Get(id); } @@ -139,7 +139,7 @@ namespace Umbraco.Core.Services if (loadBaseType) { var objectTypeId = umbracoObjectType.GetGuid(); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _entityRepository.GetByKey(key, objectTypeId); } @@ -170,7 +170,7 @@ namespace Umbraco.Core.Services if (loadBaseType) { var objectTypeId = umbracoObjectType.GetGuid(); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _entityRepository.Get(id, objectTypeId); } @@ -202,7 +202,7 @@ namespace Umbraco.Core.Services { if (loadBaseType) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _entityRepository.Get(id); } @@ -223,7 +223,7 @@ namespace Umbraco.Core.Services /// An public virtual IUmbracoEntity GetParent(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var entity = _entityRepository.Get(id); if (entity.ParentId == -1 || entity.ParentId == -20 || entity.ParentId == -21) @@ -241,7 +241,7 @@ namespace Umbraco.Core.Services /// An public virtual IUmbracoEntity GetParent(int id, UmbracoObjectTypes umbracoObjectType) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var entity = _entityRepository.Get(id); if (entity.ParentId == -1 || entity.ParentId == -20 || entity.ParentId == -21) @@ -259,7 +259,7 @@ namespace Umbraco.Core.Services /// An enumerable list of objects public virtual IEnumerable GetChildren(int parentId) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var query = Query().Where(x => x.ParentId == parentId); return _entityRepository.GetByQuery(query); @@ -275,7 +275,7 @@ namespace Umbraco.Core.Services public virtual IEnumerable GetChildren(int parentId, UmbracoObjectTypes umbracoObjectType) { var objectTypeId = umbracoObjectType.GetGuid(); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var query = Query().Where(x => x.ParentId == parentId); return _entityRepository.GetByQuery(query, objectTypeId).ToList(); // run within using! // run within using! @@ -289,7 +289,7 @@ namespace Umbraco.Core.Services /// An enumerable list of objects public virtual IEnumerable GetDescendents(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var entity = _entityRepository.Get(id); var pathMatch = entity.Path + ","; @@ -307,7 +307,7 @@ namespace Umbraco.Core.Services public virtual IEnumerable GetDescendents(int id, UmbracoObjectTypes umbracoObjectType) { var objectTypeId = umbracoObjectType.GetGuid(); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var entity = _entityRepository.Get(id); var query = Query().Where(x => x.Path.StartsWith(entity.Path) && x.Id != id); @@ -331,7 +331,7 @@ namespace Umbraco.Core.Services string orderBy = "SortOrder", Direction orderDirection = Direction.Ascending, string filter = "") { var objectTypeId = umbracoObjectType.GetGuid(); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var query = Query().Where(x => x.ParentId == parentId && x.Trashed == false); @@ -362,7 +362,7 @@ namespace Umbraco.Core.Services string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "") { var objectTypeId = umbracoObjectType.GetGuid(); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var query = Query(); //if the id is System Root, then just get all @@ -405,7 +405,7 @@ namespace Umbraco.Core.Services var objectTypeId = umbracoObjectType.GetGuid(); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var query = Query(); if (idsA.All(x => x != Constants.System.Root)) @@ -462,7 +462,7 @@ namespace Umbraco.Core.Services string orderBy = "path", Direction orderDirection = Direction.Ascending, string filter = "", bool includeTrashed = true) { var objectTypeId = umbracoObjectType.GetGuid(); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var query = Query(); //don't include trashed if specfied @@ -491,7 +491,7 @@ namespace Umbraco.Core.Services public virtual IEnumerable GetRootEntities(UmbracoObjectTypes umbracoObjectType) { var objectTypeId = umbracoObjectType.GetGuid(); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _entityRepository.GetByQuery(QueryRootEntity, objectTypeId); } @@ -527,7 +527,7 @@ namespace Umbraco.Core.Services throw new NotSupportedException("The passed in type is not supported"); var objectTypeId = umbracoObjectType.GetGuid(); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _entityRepository.GetAll(objectTypeId, ids); } @@ -542,7 +542,7 @@ namespace Umbraco.Core.Services throw new NotSupportedException("The passed in type is not supported"); var objectTypeId = umbracoObjectType.GetGuid(); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _entityRepository.GetAll(objectTypeId, keys); } @@ -556,7 +556,7 @@ namespace Umbraco.Core.Services throw new NotSupportedException("The passed in type is not supported."); var objectTypeId = umbracoObjectType.GetGuid(); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _entityRepository.GetAllPaths(objectTypeId, ids); } @@ -570,7 +570,7 @@ namespace Umbraco.Core.Services throw new NotSupportedException("The passed in type is not supported."); var objectTypeId = umbracoObjectType.GetGuid(); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _entityRepository.GetAllPaths(objectTypeId, keys); } @@ -591,7 +591,7 @@ namespace Umbraco.Core.Services if (typeFullName == null || _supportedObjectTypes.ContainsKey(typeFullName) == false) throw new NotSupportedException("The passed in type is not supported"); - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _entityRepository.GetAll(objectTypeId, ids); } @@ -604,7 +604,7 @@ namespace Umbraco.Core.Services /// public virtual UmbracoObjectTypes GetObjectType(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var sql = scope.SqlContext.Sql() .Select("nodeObjectType") @@ -623,7 +623,7 @@ namespace Umbraco.Core.Services /// public virtual UmbracoObjectTypes GetObjectType(Guid key) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var sql = scope.SqlContext.Sql() .Select("nodeObjectType") @@ -682,7 +682,7 @@ namespace Umbraco.Core.Services public bool Exists(Guid key) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var exists = _entityRepository.Exists(key); return exists; @@ -691,7 +691,7 @@ namespace Umbraco.Core.Services public bool Exists(int id) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { var exists = _entityRepository.Exists(id); return exists; diff --git a/src/Umbraco.Core/Services/ExternalLoginService.cs b/src/Umbraco.Core/Services/ExternalLoginService.cs index f0cfa5562e..09460a9f04 100644 --- a/src/Umbraco.Core/Services/ExternalLoginService.cs +++ b/src/Umbraco.Core/Services/ExternalLoginService.cs @@ -27,7 +27,7 @@ namespace Umbraco.Core.Services /// public IEnumerable GetAll(int userId) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _externalLoginRepository.Get(Query().Where(x => x.UserId == userId)) .ToList(); // ToList is important here, must evaluate within uow! // ToList is important here, must evaluate within uow! @@ -42,7 +42,7 @@ namespace Umbraco.Core.Services /// public IEnumerable Find(UserLoginInfo login) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _externalLoginRepository.Get(Query().Where(x => x.ProviderKey == login.ProviderKey && x.LoginProvider == login.LoginProvider)) .ToList(); // ToList is important here, must evaluate within uow! // ToList is important here, must evaluate within uow! diff --git a/src/Umbraco.Core/Services/FileService.cs b/src/Umbraco.Core/Services/FileService.cs index 4b05768454..1cb5de6938 100644 --- a/src/Umbraco.Core/Services/FileService.cs +++ b/src/Umbraco.Core/Services/FileService.cs @@ -53,7 +53,7 @@ namespace Umbraco.Core.Services /// An enumerable list of objects public IEnumerable GetStylesheets(params string[] names) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _stylesheetRepository.GetMany(names); } @@ -66,7 +66,7 @@ namespace Umbraco.Core.Services /// A object public Stylesheet GetStylesheetByName(string name) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _stylesheetRepository.Get(name); } @@ -137,7 +137,7 @@ namespace Umbraco.Core.Services /// True if Stylesheet is valid, otherwise false public bool ValidateStylesheet(Stylesheet stylesheet) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _stylesheetRepository.ValidateStylesheet(stylesheet); } @@ -145,7 +145,7 @@ namespace Umbraco.Core.Services public Stream GetStylesheetFileContentStream(string filepath) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _stylesheetRepository.GetFileContentStream(filepath); } @@ -162,7 +162,7 @@ namespace Umbraco.Core.Services public long GetStylesheetFileSize(string filepath) { - using (var scope = ScopeProvider.CreateScope(readOnly: true)) + using (var scope = ScopeProvider.CreateScope(autoComplete: true)) { return _stylesheetRepository.GetFileSize(filepath); } @@ -178,7 +178,7 @@ namespace Umbraco.Core.Services /// An enumerable list of objects public IEnumerable