/// <summary> /// Return the result of the <paramref name="query" /> from the cache. If the query is not cached /// yet, the query is materialized asynchronously and cached before being returned. /// </summary> /// <typeparam name="T">Generic type parameter.</typeparam> /// <param name="query">The query to cache in the QueryCacheManager.</param> /// <param name="absoluteExpiration">The fixed date and time at which the cache entry will expire.</param> /// <param name="tags"> /// A variable-length parameters list containing tags to expire cached /// entries. /// </param> /// <returns>The result of the query.</returns> public static Task <T> FromCacheAsync <T>(this QueryDeferred <T> query, DateTimeOffset absoluteExpiration, params string[] tags) { var key = QueryCacheManager.GetCacheKey(query, tags); var result = Task.Run(() => { var item = QueryCacheManager.Cache.Get(key); if (item == null) { item = query.Execute(); item = QueryCacheManager.Cache.AddOrGetExisting(key, item ?? DBNull.Value, absoluteExpiration) ?? item; QueryCacheManager.AddCacheTag(key, tags); } else { if (item == DBNull.Value) { item = null; } } return((T)item); }); return(result); }
/// <summary> /// Return the result of the <paramref name="query" /> from the cache. If the query is not cached /// yet, the query is materialized and cached before being returned. /// </summary> /// <typeparam name="T">Generic type parameter.</typeparam> /// <param name="query">The query to cache in the QueryCacheManager.</param> /// <param name="absoluteExpiration">The fixed date and time at which the cache entry will expire.</param> /// <param name="tags"> /// A variable-length parameters list containing tags to expire cached /// entries. /// </param> /// <returns>The result of the query.</returns> public static IEnumerable<T> FromCache<T>(this IQueryable<T> query, DateTimeOffset absoluteExpiration, params string[] tags) where T : class { var key = QueryCacheManager.GetCacheKey(query, tags); var item = QueryCacheManager.Cache.Get(key); if (item == null) { item = query.AsNoTracking().ToList(); item = QueryCacheManager.Cache.AddOrGetExisting(key, item, absoluteExpiration) ?? item; QueryCacheManager.AddCacheTag(key, tags); } return (IEnumerable<T>) item; }
/// <summary> /// Return the result of the <paramref name="query" /> from the cache. If the query is not cached /// yet, the query is materialized and cached before being returned. /// </summary> /// <typeparam name="T">The generic type of the query.</typeparam> /// <param name="query">The query to cache in the QueryCacheManager.</param> /// <param name="policy">The policy to use to cache the query.</param> /// <param name="tags"> /// A variable-length parameters list containing tags to expire cached /// entries. /// </param> /// <returns>The result of the query.</returns> public static IEnumerable<T> FromCache<T>(this IQueryable<T> query, CacheItemPolicy policy, params string[] tags) where T : class { var key = QueryCacheManager.GetCacheKey(query, tags); var item = QueryCacheManager.Cache.Get(key); if (item == null) { item = query.AsNoTracking().ToList(); item = QueryCacheManager.Cache.AddOrGetExisting(key, item, policy) ?? item; QueryCacheManager.AddCacheTag(key, tags); } return (IEnumerable<T>) item; }
/// <summary> /// Return the result of the <paramref name="query" /> from the cache. If the query is not cached /// yet, the query is materialized asynchronously and cached before being returned. /// </summary> /// <typeparam name="T">Generic type parameter.</typeparam> /// <param name="query">The query to cache in the QueryCacheManager.</param> /// <param name="absoluteExpiration">The fixed date and time at which the cache entry will expire.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="tags"> /// A variable-length parameters list containing tags to expire cached /// entries. /// </param> /// <returns>The result of the query.</returns> public static async Task <IEnumerable <T> > FromCacheAsync <T>(this IQueryable <T> query, DateTimeOffset absoluteExpiration, CancellationToken cancellationToken = default(CancellationToken), params string[] tags) where T : class { var key = QueryCacheManager.GetCacheKey(query, tags); var item = QueryCacheManager.Cache.Get(key); if (item == null) { item = await query.AsNoTracking().ToListAsync(cancellationToken).ConfigureAwait(false); item = QueryCacheManager.Cache.AddOrGetExisting(key, item, absoluteExpiration) ?? item; QueryCacheManager.AddCacheTag(key, tags); } return((IEnumerable <T>)item); }
/// <summary> /// Return the result of the <paramref name="query" /> from the cache. If the query is not cached /// yet, the query is materialized asynchronously and cached before being returned. /// </summary> /// <typeparam name="T">Generic type parameter.</typeparam> /// <param name="query">The query to cache in the QueryCacheManager.</param> /// <param name="absoluteExpiration">The fixed date and time at which the cache entry will expire.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <param name="tags"> /// A variable-length parameters list containing tags to expire cached /// entries. /// </param> /// <returns>The result of the query.</returns> public static async Task <T> FromCacheAsync <T>(this QueryDeferred <T> query, DateTimeOffset absoluteExpiration, CancellationToken cancellationToken = default(CancellationToken), params string[] tags) { var key = QueryCacheManager.GetCacheKey(query, tags); var item = QueryCacheManager.Cache.Get(key); if (item == null) { item = await query.ExecuteAsync(cancellationToken).ConfigureAwait(false); item = QueryCacheManager.Cache.AddOrGetExisting(key, item ?? DBNull.Value, absoluteExpiration) ?? item; QueryCacheManager.AddCacheTag(key, tags); } else { if (item == DBNull.Value) { item = null; } } return((T)item); }
/// <summary> /// Return the result of the <paramref name="query" /> from the cache. If the query is not cached /// yet, the query is materialized and cached before being returned. /// </summary> /// <typeparam name="T">The generic type of the query.</typeparam> /// <param name="query">The query to cache in the QueryCacheManager.</param> /// <param name="policy">The policy to use to cache the query.</param> /// <param name="tags"> /// A variable-length parameters list containing tags to expire cached /// entries. /// </param> /// <returns>The result of the query.</returns> public static T FromCache <T>(this QueryDeferred <T> query, CacheItemPolicy policy, params string[] tags) { var key = QueryCacheManager.GetCacheKey(query, tags); var item = QueryCacheManager.Cache.Get(key); if (item == null) { item = query.Execute(); item = QueryCacheManager.Cache.AddOrGetExisting(key, item ?? DBNull.Value, policy) ?? item; QueryCacheManager.AddCacheTag(key, tags); } else { if (item == DBNull.Value) { item = null; } } return((T)item); }
// Main implementation private static IEnumerable<T> FromCacheImplementation<T>(CachingMethod cachingMethod, IQueryable<T> query, out string cacheKey, CachingOptions options) where T : class { Logger.Log( "Performing " + cachingMethod + " for " + query.ToString() + " with options " + options.ToLog() + ".", LogLevel.Trace ); // Create NCache entry options CachingOptions optionsCloned = (CachingOptions)options.Clone(); cacheKey = null; string queryStoreKey = null; if (cachingMethod != CachingMethod.LoadIntoCache) { // Verify if query can be fetched seperately string pkCacheKey; if (QueryHelper.CanDirectPkFetch(query, optionsCloned, out pkCacheKey)) { object pkItem; if (QueryCacheManager.Cache.TryGetValue(pkCacheKey, out pkItem)) { List<T> resultSetPk = new List<T>(); List<T> resultSetPkTracked = new List<T>(); var stateManagerPk = query.GetStateManager(); resultSetPk.Add((T)pkItem); foreach (var entity in resultSetPk) { resultSetPkTracked.Add(((StateManager)stateManagerPk).GetRefValue(entity)); } return resultSetPkTracked; } } } bool cacheHit = false; IDictionary cacheResult = null; queryStoreKey = QueryCacheManager.GetQueryCacheKey(query, optionsCloned.QueryIdentifier); if (optionsCloned.StoreAs == StoreAs.Collection || optionsCloned.QueryIdentifier == null) { if (optionsCloned.StoreAs == StoreAs.Collection) cacheKey = queryStoreKey; if (optionsCloned.QueryIdentifier == null) optionsCloned.QueryIdentifier = queryStoreKey; } // Check in cache if (cachingMethod != CachingMethod.LoadIntoCache) { cacheHit = QueryCacheManager.Cache.GetByKey(queryStoreKey, out cacheResult); } // If not found in cache go for db if (!cacheHit) { var enumerableSet = query.AsEnumerable<T>(); CacheDependency dbDependency = null; if (optionsCloned.CreateDbDependency) { RelationalQueryContext queryContext = null; IRelationalCommand command = query.CreateCommand(out queryContext); string connectionString = queryContext.Connection.ConnectionString; dbDependency = GetDependency(NCacheConfiguration.DatabaseType, command.CommandText, connectionString); } return new NCacheEnumerable<T>(queryStoreKey, query, enumerableSet, optionsCloned, dbDependency); } // data is found in cache return result set else { // Assume its a collection if (cacheResult.Count == 1) { foreach (var item in cacheResult.Values) { CacheEntry entry = item as CacheEntry; if (entry != null) { // Confirmed stored as collection just return the value after casting IEnumerable<T> resultSetC = (IEnumerable<T>)entry.Value; // [Umer] i know this tracking is costly but there is no other solution var resultSetCTracked = new List<T>(); var stateManagerC = query.GetStateManager(); foreach (var entity in resultSetC) { resultSetCTracked.Add(((StateManager)stateManagerC).GetRefValue(entity)); } return resultSetCTracked; } break; } } var resultSetSE = cacheResult.Values.Cast<T>(); // [Umer] i know this tracking is costly but there is no other solution var resultSetSETracked = new List<T>(); var stateManagerSE = query.GetStateManager(); foreach (var entity in resultSetSE) { resultSetSETracked.Add(((StateManager)stateManagerSE).GetRefValue(entity)); } return resultSetSETracked; } }
// Main implementation private static T FromCacheImplementation <T>(CachingMethod cachingMethod, QueryDeferred <T> query, out string cacheKey, CachingOptions options) { Logger.Log( "Performing " + cachingMethod + " for " + query.ToString() + " with options " + options.ToLog() + ".", Microsoft.Extensions.Logging.LogLevel.Trace ); options = (CachingOptions)options.Clone(); // Always store as collection options.StoreAs = StoreAs.Collection; bool cacheHit = false; IDictionary cacheResult = default(Hashtable); cacheKey = QueryCacheManager.GetQueryCacheKey(query.Query, options.QueryIdentifier); // If user has specified tag, leave it as it is // Otherwise overwrite it with 'cacheKey' options.QueryIdentifier = options.QueryIdentifier ?? cacheKey; /* NOTE: If user stored result with a tag and is trying to query * it without the tag, it's a different query so don't * worry about that. */ // Get result into 'cacheResult' hashtable if it exists if (cachingMethod == CachingMethod.FromCache) { // Get by the tag (more reliable) cacheHit = QueryCacheManager.Cache.GetByKey(options.QueryIdentifier, out cacheResult); } // If result wasn't found OR result was meant to be stored fresh if (cachingMethod == CachingMethod.LoadIntoCache || !cacheHit) { CacheDependency dbDependency = null; if (options.CreateDbDependency) { IRelationalCommand command = query.Query.CreateCommand(out RelationalQueryContext queryContext); string connectionString = queryContext.Connection.ConnectionString; dbDependency = GetDependency(NCacheConfiguration.DatabaseType, command.CommandText, connectionString); } object item = query.Execute(); QueryCacheManager.Cache.SetAsCacheEntry(cacheKey, item ?? Null.Value, options, dbDependency); return(item == null ? default(T) : (T)item); } // If result was meant to be fetched instead of stored fresh AND it was found (somewhat) else { object returnVal = default(T); if (cacheResult != default(Hashtable)) { returnVal = cacheResult.Values.Cast <CacheEntry>().FirstOrDefault().Value; } return(returnVal != null ? (returnVal is Null ? default(T) : (T)returnVal) : default(T)); } }