using System; using System.Linq; using System.Linq.Expressions; using Composite.Data; using Composite.Data.Caching; using Composite.Data.Foundation; using Composite.Core.Types; namespace Composite.Examples.Caching { public class QueryCache where TDataType : class, IData { private readonly Cache> _innerCache; private readonly Expression> _propertyGetter; private Func _compiledExpression; private readonly bool _typeIsLocalizable; public QueryCache(Expression> propertyGetter) : this("Unnamed cache", propertyGetter, 1000) { } public QueryCache(string name, Expression> propertyGetter, int size) { _innerCache = new Cache>(name, size); _propertyGetter = propertyGetter; DataEventSystemFacade.SubscribeToDataAfterAdd(OnDataChanged, true); DataEventSystemFacade.SubscribeToDataAfterUpdate(OnDataChanged, true); DataEventSystemFacade.SubscribeToDataDeleted(OnDataChanged, true); _typeIsLocalizable = DataLocalizationFacade.IsLocalized(typeof(TDataType)); } private void OnDataChanged(object sender, DataEventArgs dataeventargs) { var data = dataeventargs.Data as TDataType; if (data == null) { return; } string cacheKey = GetCacheKey(GetKey(data)); lock (this) { _innerCache.Remove(cacheKey); } } public TDataType Get(TPropertyType key, bool forReadOnlyUsage) { TDataType result; string cacheKey = GetCacheKey(key); var cacheRecord = _innerCache.Get(cacheKey); if (cacheRecord != null) { result = cacheRecord.Value; } else lock (this) { cacheRecord = _innerCache.Get(cacheKey); if (cacheRecord != null) { result = cacheRecord.Value; } else { ParameterExpression parameter = _propertyGetter.Parameters[0]; var newBody = Expression.Equal(_propertyGetter.Body, Expression.Constant(key, typeof(TPropertyType))); var newLabda = Expression.Lambda(newBody, new[] { parameter }) as Expression>; result = DataFacade.GetData(false).Where(newLabda).FirstOrDefault(); _innerCache.Add(cacheKey, new ExtendedNullable { Value = result }); } } return result == null || forReadOnlyUsage ? result : DataWrappingFacade.Wrap(result); } public TDataType this[TPropertyType key] { get { return Get(key, false); } } private TPropertyType GetKey(TDataType dataItem) { if (_compiledExpression == null) { _compiledExpression = _propertyGetter.Compile(); } return _compiledExpression.Invoke(dataItem); } private string GetCacheKey(TPropertyType key) { string dataScope = DataScopeManager.MapByType(typeof(TDataType)).ToString(); string result = key + dataScope; if (_typeIsLocalizable) { result += LocalizationScopeManager.MapByType(typeof(TDataType)).ToString(); } return result; } } }