oops! long time ago with the original 7.3 refactor of runtime caches, before we fixed deep cloning, the changes made just used normal http runtime cache, but with the deep cloning fixes these were not carried over. This fixes that by forcing the base RepositoryBase to use a DeepCloneRuntimeCacheProvider which is a wrapper for the normal runtime cache but ensures deep cloning in/out and resets dirty properties.

This commit is contained in:
Shannon
2015-05-18 16:03:25 +10:00
parent 76fb595a55
commit b01f8799ae
2 changed files with 131 additions and 1 deletions

View File

@@ -0,0 +1,126 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Caching;
using Umbraco.Core.Cache;
using Umbraco.Core.Models;
using Umbraco.Core.Models.EntityBase;
namespace Umbraco.Core.Persistence.Repositories
{
/// <summary>
/// Ensures that all inserts and returns are a deep cloned copy of the item when
/// the item is IDeepCloneable
/// </summary>
internal class DeepCloneRuntimeCacheProvider : IRuntimeCacheProvider
{
private readonly IRuntimeCacheProvider _innerProvider;
public DeepCloneRuntimeCacheProvider(IRuntimeCacheProvider innerProvider)
{
_innerProvider = innerProvider;
}
#region Clear - doesn't require any changes
public void ClearAllCache()
{
_innerProvider.ClearAllCache();
}
public void ClearCacheItem(string key)
{
_innerProvider.ClearCacheItem(key);
}
public void ClearCacheObjectTypes(string typeName)
{
_innerProvider.ClearCacheObjectTypes(typeName);
}
public void ClearCacheObjectTypes<T>()
{
_innerProvider.ClearCacheObjectTypes<T>();
}
public void ClearCacheObjectTypes<T>(Func<string, T, bool> predicate)
{
_innerProvider.ClearCacheObjectTypes<T>(predicate);
}
public void ClearCacheByKeySearch(string keyStartsWith)
{
_innerProvider.ClearCacheByKeySearch(keyStartsWith);
}
public void ClearCacheByKeyExpression(string regexString)
{
_innerProvider.ClearCacheByKeyExpression(regexString);
}
#endregion
public IEnumerable<object> GetCacheItemsByKeySearch(string keyStartsWith)
{
return _innerProvider.GetCacheItemsByKeySearch(keyStartsWith)
.Select(CheckCloneableAndTracksChanges);
}
public IEnumerable<object> GetCacheItemsByKeyExpression(string regexString)
{
return _innerProvider.GetCacheItemsByKeyExpression(regexString)
.Select(CheckCloneableAndTracksChanges);
}
public object GetCacheItem(string cacheKey)
{
var item = _innerProvider.GetCacheItem(cacheKey);
return CheckCloneableAndTracksChanges(item);
}
public object GetCacheItem(string cacheKey, Func<object> getCacheItem)
{
return _innerProvider.GetCacheItem(cacheKey, () =>
{
//Resolve the item but returned the cloned/reset item
var item = getCacheItem();
return CheckCloneableAndTracksChanges(item);
});
}
public object GetCacheItem(string cacheKey, Func<object> getCacheItem, TimeSpan? timeout, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null)
{
return _innerProvider.GetCacheItem(cacheKey, () =>
{
//Resolve the item but returned the cloned/reset item
var item = getCacheItem();
return CheckCloneableAndTracksChanges(item);
}, timeout, isSliding, priority, removedCallback, dependentFiles);
}
public void InsertCacheItem(string cacheKey, Func<object> getCacheItem, TimeSpan? timeout = null, bool isSliding = false, CacheItemPriority priority = CacheItemPriority.Normal, CacheItemRemovedCallback removedCallback = null, string[] dependentFiles = null)
{
_innerProvider.InsertCacheItem(cacheKey, () =>
{
//Resolve the item but returned the cloned/reset item
var item = getCacheItem();
return CheckCloneableAndTracksChanges(item);
}, timeout, isSliding, priority, removedCallback, dependentFiles);
}
private static object CheckCloneableAndTracksChanges(object input)
{
var entity = input as IDeepCloneable;
if (entity == null) return input;
var cloned = entity.DeepClone();
//on initial construction we don't want to have dirty properties tracked
// http://issues.umbraco.org/issue/U4-1946
var tracksChanges = cloned as TracksChangesEntityBase;
if (tracksChanges != null)
{
tracksChanges.ResetDirtyProperties(false);
return tracksChanges;
}
return cloned;
}
}
}

View File

@@ -22,7 +22,11 @@ namespace Umbraco.Core.Persistence.Repositories
if (logger == null) throw new ArgumentNullException("logger");
Logger = logger;
_work = work;
_cache = cache;
//IMPORTANT: We will force the DeepCloneRuntimeCacheProvider to be used here which is a wrapper for the underlying
// runtime cache to ensure that anything that can be deep cloned in/out is done so, this also ensures that our tracks
// changes entities are reset.
_cache = new CacheHelper(new DeepCloneRuntimeCacheProvider(cache.RuntimeCache), cache.StaticCache, cache.RequestCache);
}
/// <summary>