/// <summary> /// Gets the value associated with the specified key as string. /// </summary> /// <param name="key">The key of the value to get.</param> /// <param name="cachePolicy">Defines the expiration mode of the cache item.</param> public string GetValueAsString(string key, EFCachePolicy cachePolicy) { var value = _database.StringGet(key); refreshCacheTimeout(key, value, cachePolicy); return(value); }
/// <summary> /// Gets the value associated with the specified key. /// </summary> /// <param name="key">The key of the value to get.</param> /// <param name="cachePolicy">Defines the expiration mode of the cache item.</param> public object Get(string key, EFCachePolicy cachePolicy) { var value = _database.StringGet(key); refreshCacheTimeout(key, value, cachePolicy); return(value.HasValue ? _serializationProvider.Deserialize(value) : null); }
/// <summary> /// Adds a new item to the cache. /// </summary> /// <param name="cacheKey">key</param> /// <param name="value">value</param> /// <param name="cachePolicy">Defines the expiration mode of the cache item.</param> public void InsertValue(EFCacheKey cacheKey, EFCachedData value, EFCachePolicy cachePolicy) { _readerWriterLockProvider.TryWriteLocked(() => { if (value == null) { value = new EFCachedData { IsNull = true }; } var options = new MemoryCacheEntryOptions { Size = 1 }; if (cachePolicy.CacheExpirationMode == CacheExpirationMode.Absolute) { options.AbsoluteExpirationRelativeToNow = cachePolicy.CacheTimeout; } else { options.SlidingExpiration = cachePolicy.CacheTimeout; } foreach (var rootCacheKey in cacheKey.CacheDependencies) { options.ExpirationTokens.Add(_signal.GetChangeToken(rootCacheKey)); } _memoryCache.Set(cacheKey.KeyHash, value, options); }); }
/// <summary> /// Returns a new query where the entities returned by it will be cached only for 30 minutes. /// </summary> /// <typeparam name="TType">Entity type.</typeparam> /// <param name="query">The input EF query.</param> /// <returns>Provides functionality to evaluate queries against a specific data source.</returns> public static IQueryable <TType> Cacheable <TType>( this DbSet <TType> query) where TType : class { sanityCheck(query); return(query.markAsNoTracking().TagWith(EFCachePolicy.Configure(options => options.ExpirationMode(CacheExpirationMode.Absolute).Timeout(_thirtyMinutes).DefaultCacheableMethod(true)))); }
/// <summary> /// Returns a new query where the entities returned by it will be cached only for 30 minutes. /// </summary> /// <typeparam name="TType">Entity type.</typeparam> /// <param name="query">The input EF query.</param> /// <param name="methodName">Tells the compiler to insert the name of the containing member instead of a parameter’s default value</param> /// <param name="lineNumber">Tells the compiler to insert the line number of the containing member instead of a parameter’s default value</param> /// <returns>Provides functionality to evaluate queries against a specific data source.</returns> public static IQueryable <TType> Cacheable <TType>( this DbSet <TType> query, [CallerMemberName] string methodName = null, [CallerLineNumber] int lineNumber = 0) where TType : class { sanityCheck(query); return(query.markAsNoTracking().TagWith(EFCachePolicy.Configure(options => options.ExpirationMode(CacheExpirationMode.Absolute).Timeout(_thirtyMinutes).CallerMemberName(methodName).CallerLineNumber(lineNumber)))); }
/// <summary> /// Returns a new query where the entities returned will be cached. /// </summary> /// <typeparam name="TType">Entity type.</typeparam> /// <param name="query">The input EF query.</param> /// <param name="expirationMode">Defines the expiration mode of the cache item.</param> /// <param name="timeout">The expiration timeout.</param> /// <returns>Provides functionality to evaluate queries against a specific data source.</returns> public static IQueryable <TType> Cacheable <TType>( this IQueryable <TType> query, CacheExpirationMode expirationMode, TimeSpan timeout) { sanityCheck(query); return(query.markAsNoTracking().TagWith(EFCachePolicy.Configure(options => options.ExpirationMode(expirationMode).Timeout(timeout)))); }
/// <summary> /// Adds a new item to the cache. /// </summary> /// <param name="cacheKey">key</param> /// <param name="value">value</param> /// <param name="cachePolicy">Defines the expiration mode of the cache item.</param> public void InsertValue(EFCacheKey cacheKey, EFCachedData value, EFCachePolicy cachePolicy) { _readerWriterLockProvider.TryWriteLocked(() => { if (value == null) { value = new EFCachedData { IsNull = true }; } var keyHash = cacheKey.KeyHash; foreach (var rootCacheKey in cacheKey.CacheDependencies) { var items = _easyCachingProvider.Get <HashSet <string> >(rootCacheKey); if (items.IsNull) { _easyCachingProvider.Set(rootCacheKey, new HashSet <string> { keyHash }, cachePolicy.CacheTimeout); } else { items.Value.Add(keyHash); _easyCachingProvider.Set(rootCacheKey, items.Value, cachePolicy.CacheTimeout); } } // We don't support Sliding Expiration at this time. -> https://github.com/dotnetcore/EasyCaching/issues/113 _easyCachingProvider.Set(keyHash, value, cachePolicy.CacheTimeout); }); }
/// <summary> /// Returns a new query where the entities returned will be cached. /// </summary> /// <typeparam name="TType">Entity type.</typeparam> /// <param name="query">The input EF query.</param> /// <param name="expirationMode">Defines the expiration mode of the cache item.</param> /// <param name="timeout">The expiration timeout.</param> /// <param name="methodName">Tells the compiler to insert the name of the containing member instead of a parameter’s default value</param> /// <param name="lineNumber">Tells the compiler to insert the line number of the containing member instead of a parameter’s default value</param> /// <returns>Provides functionality to evaluate queries against a specific data source.</returns> public static IQueryable <TType> Cacheable <TType>( this IQueryable <TType> query, CacheExpirationMode expirationMode, TimeSpan timeout, [CallerMemberName] string methodName = null, [CallerLineNumber] int lineNumber = 0) { sanityCheck(query); return(query.markAsNoTracking().TagWith(EFCachePolicy.Configure(options => options.ExpirationMode(expirationMode).Timeout(timeout).CallerMemberName(methodName).CallerLineNumber(lineNumber)))); }
/// <summary> /// Determines the Expiration time of the cache. /// </summary> public static string Configure(Action <EFCachePolicy> options) { var cachePolicy = new EFCachePolicy(); options.Invoke(cachePolicy); return(cachePolicy.ToString()); }
/// <summary> /// Gets an EF query and returns its hashed key to store in the cache. /// </summary> /// <param name="command">The EF query.</param> /// <param name="context">DbContext is a combination of the Unit Of Work and Repository patterns.</param> /// <param name="cachePolicy">determines the Expiration time of the cache.</param> /// <returns>Information of the computed key of the input LINQ query.</returns> public EFCacheKey GetEFCacheKey(DbCommand command, DbContext context, EFCachePolicy cachePolicy) { if (command == null) { throw new ArgumentNullException(nameof(command)); } if (cachePolicy == null) { throw new ArgumentNullException(nameof(cachePolicy)); } //put the prefix in both places so the namespace will apply regardless of which key is used for access into the cache #pragma warning disable S125 // Sections of code should not be commented out string cacheKey = string.Empty; var cacheKeyHash = string.Empty; if (!string.IsNullOrEmpty(_keyPrefix)) { cacheKey += _keyPrefix; cacheKeyHash += _keyPrefix; } cacheKey += getCacheKey(command, cachePolicy.CacheSaltKey); cacheKeyHash += $"{XxHashUnsafe.ComputeHash(cacheKey):X}"; var cacheDependencies = _cacheDependenciesProcessor.GetCacheDependencies(command, context, cachePolicy); _logger.LogDebug($"KeyHash: {cacheKeyHash}, CacheDependencies: {string.Join(", ", cacheDependencies)}."); return(new EFCacheKey(cacheDependencies) { Key = cacheKey, KeyHash = cacheKeyHash }); }
/// <summary> /// Returns a new query where the entities returned will be cached. /// </summary> /// <typeparam name="TType">Entity type.</typeparam> /// <param name="query">The input EF query.</param> /// <param name="expirationMode">Defines the expiration mode of the cache item.</param> /// <param name="timeout">The expiration timeout.</param> /// <param name="saltKey">If you think the computed hash of the query to calculate the cache-key is not enough, set this value.</param> /// <returns>Provides functionality to evaluate queries against a specific data source.</returns> public static IQueryable <TType> Cacheable <TType>( this DbSet <TType> query, CacheExpirationMode expirationMode, TimeSpan timeout, string saltKey) where TType : class { sanityCheck(query); return(query.markAsNoTracking().TagWith(EFCachePolicy.Configure(options => options.ExpirationMode(expirationMode).Timeout(timeout).SaltKey(saltKey)))); }
/// <summary> /// Finds the related table names of the current query. /// </summary> public SortedSet <string> GetCacheDependencies(EFCachePolicy cachePolicy, SortedSet <string> tableNames, string commandText) { if (cachePolicy == null) { throw new ArgumentNullException(nameof(cachePolicy)); } var textsInsideSquareBrackets = _sqlCommandsProcessor.GetSqlCommandTableNames(commandText); var cacheDependencies = new SortedSet <string>( tableNames.Intersect(textsInsideSquareBrackets, StringComparer.OrdinalIgnoreCase), StringComparer.OrdinalIgnoreCase); if (cacheDependencies.Any()) { logProcess(tableNames, textsInsideSquareBrackets, cacheDependencies); return(cacheDependencies); } cacheDependencies = cachePolicy.CacheItemsDependencies as SortedSet <string>; if (cacheDependencies?.Any() != true) { _logger.LogDebug($"It's not possible to calculate the related table names of the current query[{commandText}]. Please use EFCachePolicy.Configure(options => options.CacheDependencies(\"real_table_name_1\", \"real_table_name_2\")) to specify them explicitly."); cacheDependencies = new SortedSet <string>(StringComparer.OrdinalIgnoreCase) { EFCachePolicy.EFUnknownsCacheDependency }; } logProcess(tableNames, textsInsideSquareBrackets, cacheDependencies); return(cacheDependencies); }
/// <summary> /// Gets an EF query and returns its hashed key to store in the cache. /// </summary> /// <param name="command">The EF query.</param> /// <param name="context">DbContext is a combination of the Unit Of Work and Repository patterns.</param> /// <param name="cachePolicy">determines the Expiration time of the cache.</param> /// <returns>Information of the computed key of the input LINQ query.</returns> public EFCacheKey GetEFCacheKey(DbCommand command, DbContext context, EFCachePolicy cachePolicy) { if (command == null) { throw new ArgumentNullException(nameof(command)); } if (cachePolicy == null) { throw new ArgumentNullException(nameof(cachePolicy)); } var cacheKey = getCacheKey(command, cachePolicy.CacheSaltKey); var cacheKeyHash = !string.IsNullOrEmpty(_cacheSettings.CacheKeyPrefix) ? $"{_cacheSettings.CacheKeyPrefix}{_hashProvider.ComputeHash(cacheKey):X}" : $"{_hashProvider.ComputeHash(cacheKey):X}"; var cacheDependencies = _cacheDependenciesProcessor.GetCacheDependencies(command, context, cachePolicy); _logger.LogDebug($"KeyHash: {cacheKeyHash}, CacheDependencies: {string.Join(", ", cacheDependencies)}."); return(new EFCacheKey(cacheDependencies) { KeyHash = cacheKeyHash }); }
/// <summary> /// Returns a new query where the entities returned will be cached. /// </summary> /// <typeparam name="TType">Entity type.</typeparam> /// <param name="query">The input EF query.</param> /// <param name="expirationMode">Defines the expiration mode of the cache item.</param> /// <param name="timeout">The expiration timeout.</param> /// <param name="saltKey">If you think the computed hash of the query to calculate the cache-key is not enough, set this value.</param> /// <returns>Provides functionality to evaluate queries against a specific data source.</returns> public static IQueryable <TType> Cacheable <TType>( this IQueryable <TType> query, CacheExpirationMode expirationMode, TimeSpan timeout, string saltKey) { sanityCheck(query); return(query.TagWith(EFCachePolicy.Configure(options => options.ExpirationMode(expirationMode).Timeout(timeout).SaltKey(saltKey)))); }
/// <summary> /// Returns a new query where the entities returned will be cached. /// </summary> /// <typeparam name="TType">Entity type.</typeparam> /// <param name="query">The input EF query.</param> /// <param name="expirationMode">Defines the expiration mode of the cache item.</param> /// <param name="timeout">The expiration timeout.</param> /// <param name="cacheDependencies"> /// Set this option to the `real` related table names of the current query, if you are using an stored procedure, /// otherswise cache dependencies of normal queries will be calculated automatically. /// `cacheDependencies` determines which tables are used in this final query. /// This array will be used to invalidate the related cache of all related queries automatically. /// </param> /// <returns>Provides functionality to evaluate queries against a specific data source.</returns> public static IQueryable <TType> Cacheable <TType>( this DbSet <TType> query, CacheExpirationMode expirationMode, TimeSpan timeout, string[] cacheDependencies) where TType : class { sanityCheck(query); return(query.TagWith(EFCachePolicy.Configure(options => options.ExpirationMode(expirationMode).Timeout(timeout).CacheDependencies(cacheDependencies)))); }
/// <summary> /// Returns a new query where the entities returned by it will be cached only for 30 minutes. /// </summary> /// <typeparam name="TType">Entity type.</typeparam> /// <param name="query">The input EF query.</param> /// <returns>Provides functionality to evaluate queries against a specific data source.</returns> public static IQueryable <TType> Cacheable <TType>( this IQueryable <TType> query) { sanityCheck(query); return(query.TagWith(EFCachePolicy.Configure(options => options.ExpirationMode(CacheExpirationMode.Absolute).Timeout(_thirtyMinutes).DefaultCacheableMethod(true)))); }
/// <summary> /// Gets a cached entry by key. /// </summary> /// <param name="cacheKey">key to find</param> /// <returns>cached value</returns> /// <param name="cachePolicy">Defines the expiration mode of the cache item.</param> public EFCachedData GetValue(EFCacheKey cacheKey, EFCachePolicy cachePolicy) { return(_readerWriterLockProvider.TryReadLocked(() => { var returnValue = _easyCachingProvider.Get <EFCachedData>(cacheKey.KeyHash).Value; return returnValue; })); }
/// <summary> /// Returns a new query where the entities returned will be cached. /// </summary> /// <typeparam name="TType">Entity type.</typeparam> /// <param name="query">The input EF query.</param> /// <param name="expirationMode">Defines the expiration mode of the cache item.</param> /// <param name="timeout">The expiration timeout.</param> /// <param name="cacheDependencies"> /// Set this option to the `real` related table names of the current query, if you are using an stored procedure, /// otherswise cache dependencies of normal queries will be calculated automatically. /// `cacheDependencies` determines which tables are used in this final query. /// This array will be used to invalidate the related cache of all related queries automatically. /// </param> /// <param name="saltKey">If you think the computed hash of the query to calculate the cache-key is not enough, set this value.</param> /// <param name="methodName">Tells the compiler to insert the name of the containing member instead of a parameter’s default value</param> /// <param name="lineNumber">Tells the compiler to insert the line number of the containing member instead of a parameter’s default value</param> /// <returns>Provides functionality to evaluate queries against a specific data source.</returns> public static IQueryable <TType> Cacheable <TType>( this DbSet <TType> query, CacheExpirationMode expirationMode, TimeSpan timeout, string[] cacheDependencies, string saltKey, [CallerMemberName] string methodName = null, [CallerLineNumber] int lineNumber = 0) where TType : class { sanityCheck(query); return(query.markAsNoTracking().TagWith(EFCachePolicy.Configure(options => options.ExpirationMode(expirationMode).Timeout(timeout) .CacheDependencies(cacheDependencies).SaltKey(saltKey) .CallerMemberName(methodName).CallerLineNumber(lineNumber)))); }
/// <summary> /// Determines the Expiration time of the cache. /// </summary> public static string Configure(Action <EFCachePolicy> options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } var cachePolicy = new EFCachePolicy(); options.Invoke(cachePolicy); return(cachePolicy.ToString()); }
/// <summary> /// Adds a new item to the cache. /// </summary> /// <param name="cacheKey">key</param> /// <param name="value">value</param> /// <param name="cachePolicy">Defines the expiration mode of the cache item.</param> public void InsertValue(EFCacheKey cacheKey, EFCachedData value, EFCachePolicy cachePolicy) { _readerWriterLockProvider.TryWriteLocked(() => { if (value == null) { value = new EFCachedData { IsNull = true }; } _redisDbCache.Set(getKey(cacheKey), value, cachePolicy); }); }
/// <summary> /// Gets an EF query and returns its hashed key to store in the cache. /// </summary> /// <param name="command">The EF query.</param> /// <param name="context">DbContext is a combination of the Unit Of Work and Repository patterns.</param> /// <param name="cachePolicy">determines the Expiration time of the cache.</param> /// <returns>Information of the computed key of the input LINQ query.</returns> public EFCacheKey GetEFCacheKey(DbCommand command, DbContext context, EFCachePolicy cachePolicy) { var cacheKey = getCacheKey(command, cachePolicy.CacheSaltKey); var cacheKeyHash = $"{XxHashUnsafe.ComputeHash(cacheKey):X}"; var cacheDependencies = _cacheDependenciesProcessor.GetCacheDependencies(command, context, cachePolicy); _logger.LogDebug($"KeyHash: {cacheKeyHash}, CacheDependencies: {string.Join(", ", cacheDependencies)}."); return(new EFCacheKey { Key = cacheKey, KeyHash = cacheKeyHash, CacheDependencies = cacheDependencies }); }
/// <summary> /// Adds a new item to the cache. /// </summary> /// <param name="cacheKey">key</param> /// <param name="value">value</param> /// <param name="cachePolicy">Defines the expiration mode of the cache item.</param> public void InsertValue(EFCacheKey cacheKey, EFCachedData value, EFCachePolicy cachePolicy) { _readerWriterLockProvider.TryWriteLocked(() => { if (value == null) { value = new EFCachedData { IsNull = true }; } var keyHash = cacheKey.KeyHash; foreach (var rootCacheKey in cacheKey.CacheDependencies) { _dependenciesCacheManager.AddOrUpdate( rootCacheKey, new HashSet <string>(StringComparer.OrdinalIgnoreCase) { keyHash }, updateValue: set => { set.Add(keyHash); return(set); }); } if (cachePolicy == null) { _valuesCacheManager.Add(keyHash, value); } else { _valuesCacheManager.Add(new CacheItem <EFCachedData>( keyHash, value, cachePolicy.CacheExpirationMode == CacheExpirationMode.Absolute ? ExpirationMode.Absolute : ExpirationMode.Sliding, cachePolicy.CacheTimeout)); } }); }
/// <summary> /// Finds the related table names of the current query. /// </summary> public SortedSet <string> GetCacheDependencies(EFCachePolicy cachePolicy, SortedSet <string> tableNames, string commandText) { var textsInsideSquareBrackets = getSqlCommandTableNames(commandText); var cacheDependencies = new SortedSet <string>(tableNames.Intersect(textsInsideSquareBrackets)); if (cacheDependencies.Any()) { logProcess(tableNames, textsInsideSquareBrackets, cacheDependencies); return(cacheDependencies); } cacheDependencies = cachePolicy.CacheItemsDependencies as SortedSet <string>; if (cacheDependencies?.Any() != true) { _logger.LogInformation($"It's not possible to calculate the related table names of the current query[{commandText}]. Please use EFCachePolicy.Configure(options => options.CacheDependencies(\"real_table_name_1\", \"real_table_name_2\")) to specify them explicitly."); cacheDependencies = new SortedSet <string> { EFCachePolicy.EFUnknownsCacheDependency }; } logProcess(tableNames, textsInsideSquareBrackets, cacheDependencies); return(cacheDependencies); }
/// <summary> /// Gets an EF query and returns its hashed key to store in the cache. /// </summary> /// <param name="command">The EF query.</param> /// <param name="context">DbContext is a combination of the Unit Of Work and Repository patterns.</param> /// <param name="cachePolicy">determines the Expiration time of the cache.</param> /// <returns>Information of the computed key of the input LINQ query.</returns> public EFCacheKey GetEFCacheKey(DbCommand command, DbContext context, EFCachePolicy cachePolicy) { if (command == null) { throw new ArgumentNullException(nameof(command)); } if (cachePolicy == null) { throw new ArgumentNullException(nameof(cachePolicy)); } var cacheKey = getCacheKey(command, cachePolicy.CacheSaltKey); var cacheKeyHash = $"{XxHashUnsafe.ComputeHash(cacheKey):X}"; var cacheDependencies = _cacheDependenciesProcessor.GetCacheDependencies(command, context, cachePolicy); _logger.LogDebug($"KeyHash: {cacheKeyHash}, CacheDependencies: {string.Join(", ", cacheDependencies)}."); return(new EFCacheKey(cacheDependencies) { Key = cacheKey, KeyHash = cacheKeyHash }); }
/// <summary> /// Finds the related table names of the current query. /// </summary> public SortedSet <string> GetCacheDependencies(DbCommand command, DbContext context, EFCachePolicy cachePolicy) { var tableNames = getAllTableNames(context); return(GetCacheDependencies(cachePolicy, tableNames, command.CommandText)); }
/// <summary> /// Invalidates all of the cache entries which are dependent on any of the specified root keys. /// </summary> public bool InvalidateCacheDependencies(DbCommand command, DbContext context, EFCachePolicy cachePolicy) { var commandText = command.CommandText; if (!IsCrudCommand(commandText)) { return(false); } var cacheDependencies = GetCacheDependencies(command, context, cachePolicy); cacheDependencies.Add(EFCachePolicy.EFUnknownsCacheDependency); _cacheServiceProvider.InvalidateCacheDependencies(new EFCacheKey { CacheDependencies = cacheDependencies }); _logger.LogInformation(CacheableEventId.QueryResultInvalidated, $"Invalidated [{string.Join(", ", cacheDependencies)}] dependencies."); return(true); }
/// <summary> /// Gets a cached entry by key. /// </summary> /// <param name="cacheKey">key to find</param> /// <returns>cached value</returns> /// <param name="cachePolicy">Defines the expiration mode of the cache item.</param> public EFCachedData GetValue(EFCacheKey cacheKey, EFCachePolicy cachePolicy) { return(_readerWriterLockProvider.TryReadLocked(() => _valuesCacheManager.Get <EFCachedData>(cacheKey.KeyHash))); }
/// <summary> /// Finds the related table names of the current query. /// </summary> public SortedSet <string> GetCacheDependencies(DbCommand command, DbContext context, EFCachePolicy cachePolicy) { if (command == null) { throw new ArgumentNullException(nameof(command)); } var tableNames = new SortedSet <string>( _sqlCommandsProcessor.GetAllTableNames(context).Select(x => x.TableName), StringComparer.OrdinalIgnoreCase); return(GetCacheDependencies(cachePolicy, tableNames, command.CommandText)); }
/// <summary> /// Gets a cached entry by key. /// </summary> /// <param name="cacheKey">key to find</param> /// <returns>cached value</returns> /// <param name="cachePolicy">Defines the expiration mode of the cache item.</param> public EFCachedData GetValue(EFCacheKey cacheKey, EFCachePolicy cachePolicy) { return(_readerWriterLockProvider.TryReadLocked(() => _redisDbCache.Get <EFCachedData>(getKey(cacheKey), cachePolicy))); }
/// <summary> /// Invalidates all of the cache entries which are dependent on any of the specified root keys. /// </summary> public bool InvalidateCacheDependencies(DbCommand command, DbContext context, EFCachePolicy cachePolicy) { if (command == null) { throw new ArgumentNullException(nameof(command)); } var commandText = command.CommandText; if (!_sqlCommandsProcessor.IsCrudCommand(commandText)) { return(false); } if (shouldSkipCacheInvalidationCommands(commandText)) { return(false); } var cacheDependencies = GetCacheDependencies(command, context, cachePolicy); cacheDependencies.Add(EFCachePolicy.EFUnknownsCacheDependency); _cacheServiceProvider.InvalidateCacheDependencies(new EFCacheKey(cacheDependencies)); _logger.LogDebug(CacheableEventId.QueryResultInvalidated, $"Invalidated [{string.Join(", ", cacheDependencies)}] dependencies."); return(true); }