UnitOfWork RIP, troubleshoot and fix, tests

This commit is contained in:
Stephan
2017-12-15 16:29:14 +01:00
parent 0ab2f6cc9f
commit bbff74fa51
79 changed files with 501 additions and 588 deletions

View File

@@ -28,9 +28,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override bool IsPublishing => ContentType.IsPublishingConst;
protected override IRepositoryCachePolicy<IContentType, int> CreateCachePolicy(IRuntimeCacheProvider runtimeCache)
protected override IRepositoryCachePolicy<IContentType, int> CreateCachePolicy()
{
return new FullDataSetRepositoryCachePolicy<IContentType, int>(runtimeCache, GetEntityId, /*expires:*/ true);
return new FullDataSetRepositoryCachePolicy<IContentType, int>(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

View File

@@ -22,7 +22,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
: base(scopeAccessor, cache, logger)
{ }
protected override IRepositoryCachePolicy<IDictionaryItem, int> CreateCachePolicy(IRuntimeCacheProvider runtimeCache)
protected override IRepositoryCachePolicy<IDictionaryItem, int> CreateCachePolicy()
{
var options = new RepositoryCachePolicyOptions
{
@@ -30,7 +30,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
GetAllCacheAllowZeroCount = true
};
return new SingleItemsOnlyRepositoryCachePolicy<IDictionaryItem, int>(runtimeCache, options);
return new SingleItemsOnlyRepositoryCachePolicy<IDictionaryItem, int>(GlobalIsolatedCache, ScopeAccessor, options);
}
#region Overrides of RepositoryBase<int,DictionaryItem>
@@ -333,7 +333,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return "cmsDictionary." + SqlSyntax.GetQuotedColumnName("id") + " in (@ids)";
}
protected override IRepositoryCachePolicy<IDictionaryItem, Guid> CreateCachePolicy(IRuntimeCacheProvider runtimeCache)
protected override IRepositoryCachePolicy<IDictionaryItem, Guid> CreateCachePolicy()
{
var options = new RepositoryCachePolicyOptions
{
@@ -341,7 +341,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
GetAllCacheAllowZeroCount = true
};
return new SingleItemsOnlyRepositoryCachePolicy<IDictionaryItem, Guid>(runtimeCache, options);
return new SingleItemsOnlyRepositoryCachePolicy<IDictionaryItem, Guid>(GlobalIsolatedCache, ScopeAccessor, options);
}
}
@@ -386,7 +386,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
return "cmsDictionary." + SqlSyntax.GetQuotedColumnName("key") + " in (@ids)";
}
protected override IRepositoryCachePolicy<IDictionaryItem, string> CreateCachePolicy(IRuntimeCacheProvider runtimeCache)
protected override IRepositoryCachePolicy<IDictionaryItem, string> CreateCachePolicy()
{
var options = new RepositoryCachePolicyOptions
{
@@ -394,7 +394,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
GetAllCacheAllowZeroCount = true
};
return new SingleItemsOnlyRepositoryCachePolicy<IDictionaryItem, string>(runtimeCache, options);
return new SingleItemsOnlyRepositoryCachePolicy<IDictionaryItem, string>(GlobalIsolatedCache, ScopeAccessor, options);
}
}
}

View File

@@ -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;

View File

@@ -20,9 +20,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
: base(scopeAccessor, cache, logger)
{ }
protected override IRepositoryCachePolicy<IDomain, int> CreateCachePolicy(IRuntimeCacheProvider runtimeCache)
protected override IRepositoryCachePolicy<IDomain, int> CreateCachePolicy()
{
return new FullDataSetRepositoryCachePolicy<IDomain, int>(runtimeCache, GetEntityId, /*expires:*/ false);
return new FullDataSetRepositoryCachePolicy<IDomain, int>(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ false);
}
protected override IDomain PerformGet(int id)

View File

@@ -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<EntityContainer, int> CreateCachePolicy()
{
return NullCache;
return NoCacheRepositoryCachePolicy<EntityContainer, int>.Instance;
}
protected override EntityContainer PerformGet(int id)

View File

@@ -22,9 +22,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
: base(scopeAccessor, cache, logger)
{ }
protected override IRepositoryCachePolicy<ILanguage, int> CreateCachePolicy(IRuntimeCacheProvider runtimeCache)
protected override IRepositoryCachePolicy<ILanguage, int> CreateCachePolicy()
{
return new FullDataSetRepositoryCachePolicy<ILanguage, int>(runtimeCache, GetEntityId, /*expires:*/ false);
return new FullDataSetRepositoryCachePolicy<ILanguage, int>(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ false);
}
#region Overrides of RepositoryBase<int,Language>

View File

@@ -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;

View File

@@ -22,9 +22,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override bool IsPublishing => MediaType.IsPublishingConst;
protected override IRepositoryCachePolicy<IMediaType, int> CreateCachePolicy(IRuntimeCacheProvider runtimeCache)
protected override IRepositoryCachePolicy<IMediaType, int> CreateCachePolicy()
{
return new FullDataSetRepositoryCachePolicy<IMediaType, int>(runtimeCache, GetEntityId, /*expires:*/ true);
return new FullDataSetRepositoryCachePolicy<IMediaType, int>(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ true);
}
protected override IMediaType PerformGet(int id)

View File

@@ -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;

View File

@@ -23,9 +23,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
protected override bool IsPublishing => MemberType.IsPublishingConst;
protected override IRepositoryCachePolicy<IMemberType, int> CreateCachePolicy(IRuntimeCacheProvider runtimeCache)
protected override IRepositoryCachePolicy<IMemberType, int> CreateCachePolicy()
{
return new FullDataSetRepositoryCachePolicy<IMemberType, int>(runtimeCache, GetEntityId, /*expires:*/ true);
return new FullDataSetRepositoryCachePolicy<IMemberType, int>(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ true);
}
protected override IMemberType PerformGet(int id)

View File

@@ -18,9 +18,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
: base(scopeAccessor, cache, logger)
{ }
protected override IRepositoryCachePolicy<PublicAccessEntry, Guid> CreateCachePolicy(IRuntimeCacheProvider runtimeCache)
protected override IRepositoryCachePolicy<PublicAccessEntry, Guid> CreateCachePolicy()
{
return new FullDataSetRepositoryCachePolicy<PublicAccessEntry, Guid>(runtimeCache, GetEntityId, /*expires:*/ false);
return new FullDataSetRepositoryCachePolicy<PublicAccessEntry, Guid>(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ false);
}
protected override PublicAccessEntry PerformGet(Guid id)

View File

@@ -22,9 +22,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
: base(scopeAccessor, cache, logger)
{ }
protected override IRepositoryCachePolicy<IRelationType, int> CreateCachePolicy(IRuntimeCacheProvider runtimeCache)
protected override IRepositoryCachePolicy<IRelationType, int> CreateCachePolicy()
{
return new FullDataSetRepositoryCachePolicy<IRelationType, int>(runtimeCache, GetEntityId, /*expires:*/ true);
return new FullDataSetRepositoryCachePolicy<IRelationType, int>(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ true);
}
#region Overrides of RepositoryBase<int,RelationType>

View File

@@ -18,7 +18,6 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
where TEntity : class, IAggregateRoot
{
private IRepositoryCachePolicy<TEntity, TId> _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<TEntity>();
protected IScopeAccessor ScopeAccessor { get; }
protected IScope AmbientScope
@@ -56,38 +57,28 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
}
/// <summary>
/// The runtime cache used for this repo by default is the isolated cache for this type
/// Gets the isolated cache.
/// </summary>
/// <remarks>Depends on the ambient scope cache mode.</remarks>
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<TEntity>();
case RepositoryCacheMode.Scoped:
provider = AmbientScope.IsolatedRuntimeCache;
break;
return AmbientScope.IsolatedRuntimeCache.GetOrCreateCache<TEntity>();
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<TEntity>();
}
// 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<TEntity, TId> CachePolicy
protected IRepositoryCachePolicy<TEntity, TId> CachePolicy
{
get
{
if (GlobalCache == CacheHelper.NoCache)
return _cachePolicy = NoCacheRepositoryCachePolicy<TEntity, TId>.Instance;
return NoCacheRepositoryCachePolicy<TEntity, TId>.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<TEntity, TId>.Instance;
break;
return NoCacheRepositoryCachePolicy<TEntity, TId>.Instance;
default:
throw new Exception("oops: cache mode.");
}
return _cachePolicy;
}
}
protected virtual IRepositoryCachePolicy<TEntity, TId> CreateCachePolicy(IRuntimeCacheProvider runtimeCache)
protected virtual IRepositoryCachePolicy<TEntity, TId> CreateCachePolicy()
{
return new DefaultRepositoryCachePolicy<TEntity, TId>(runtimeCache, DefaultOptions);
return new DefaultRepositoryCachePolicy<TEntity, TId>(GlobalIsolatedCache, ScopeAccessor, DefaultOptions);
}
/// <summary>
@@ -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);
}
/// <summary>
@@ -186,7 +173,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
/// <param name="entity"></param>
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<TEntity> PerformGetByQuery(IQuery<TEntity> query);
protected abstract bool PerformExists(TId id);
protected abstract int PerformCount(IQuery<TEntity> 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);
}
/// <summary>
/// Unit of work method that tells the repository to persist the new entity
/// </summary>
/// <param name="entity"></param>
public virtual void PersistNewItem(IEntity entity)
{
CachePolicy.Create((TEntity) entity, PersistNewItem);
}
/// <summary>
/// Unit of work method that tells the repository to persist the updated entity
/// </summary>
/// <param name="entity"></param>
public virtual void PersistUpdatedItem(IEntity entity)
{
CachePolicy.Update((TEntity) entity, PersistUpdatedItem);
}
/// <summary>
/// Unit of work method that tells the repository to persist the deletion of the entity
/// </summary>
/// <param name="entity"></param>
public virtual void PersistDeletedItem(IEntity entity)
{
CachePolicy.Delete((TEntity) entity, PersistDeletedItem);
}
}
}

View File

@@ -19,7 +19,7 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
: base(scopeAccessor, CacheHelper.CreateDisabledCacheHelper(), logger)
{ }
protected override IRepositoryCachePolicy<IServerRegistration, int> CreateCachePolicy(IRuntimeCacheProvider runtimeCache)
protected override IRepositoryCachePolicy<IServerRegistration, int> 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<IServerRegistration, int>(GlobalCache.RuntimeCache, GetEntityId, /*expires:*/ false);
return new FullDataSetRepositoryCachePolicy<IServerRegistration, int>(GlobalCache.RuntimeCache, ScopeAccessor, GetEntityId, /*expires:*/ false);
}
public void ClearCache()

View File

@@ -42,9 +42,9 @@ namespace Umbraco.Core.Persistence.Repositories.Implement
_masterPageHelper = new MasterPageHelper(_masterpagesFileSystem);
}
protected override IRepositoryCachePolicy<ITemplate, int> CreateCachePolicy(IRuntimeCacheProvider runtimeCache)
protected override IRepositoryCachePolicy<ITemplate, int> CreateCachePolicy()
{
return new FullDataSetRepositoryCachePolicy<ITemplate, int>(runtimeCache, GetEntityId, /*expires:*/ false);
return new FullDataSetRepositoryCachePolicy<ITemplate, int>(GlobalIsolatedCache, ScopeAccessor, GetEntityId, /*expires:*/ false);
}
#region Overrides of RepositoryBase<int,ITemplate>

View File

@@ -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