Example #1
0
        /// <summary>
        /// Inserts instance of an entity in the cache. Any exisiting entity will be overwritten in the cache.
        /// Entity should be a part of the database context or else the method will throw an exception.
        /// </summary>
        /// <param name="entity">Instance of the entity to be inserted.</param>
        /// <param name="cacheKey">cache key that was used to insert the entity.</param>
        /// <param name="options">Caching options to be used while storing the entity. Note that some of the options
        /// might be overridden such as StoreAs option will always be <see cref="StoreAs.SeperateEntities"/>.</param>
        public void Insert(object entity, out string cacheKey, CachingOptions options)
        {
            Logger.Log(
                "Inserting entity '" + entity + "' with options " + options.ToLog() + "",
                Microsoft.Extensions.Logging.LogLevel.Trace
                );

            if (IsValidEntity(entity))
            {
                NCacheWrapper nCacheWrapper = QueryCacheManager.Cache;

                // Generate key using the key generator from NCacheWrapper
                cacheKey = nCacheWrapper.DefaultKeyGen.GetKey(CurrentContext, entity);

                //
                // Items are stored as separate entities in this API because only separate APIs can make it
                // to this section of code. List or other similar data structures will fail on IsValidEntity
                // so only individual entities will make it to here.
                //
                nCacheWrapper.Set(cacheKey, entity, options, null, StoreAs.SeperateEntities);

                return;
            }
            else
            {
                throw new Exception("Entity type and context do not match");
            }
        }
Example #2
0
        internal static bool IsSeperateStorageEligible <T>(IQueryable <T> query, CachingOptions options)
        {
            Logger.Log(
                "IsSeparateStorageEligible with " + query.ToString() + " and " + options.ToLog() + "?",
                Microsoft.Extensions.Logging.LogLevel.Trace
                );

            IEntityType entityType = query.GetDbContext().Model.FindEntityType(query.ElementType.FullName);

            // Full Projection
            if (entityType != null)
            {
                // If User specified key based caching
                if (options.StoreAs == StoreAs.SeperateEntities)
                {
                    if (entityType.FindPrimaryKey() == null)
                    {
                        return(false);
                    }
                    else
                    {
                        return(true);
                    }
                }
                else
                {
                    return(false);
                }
            }
            else
            {
                return(false);
            }
        }
Example #3
0
        internal static bool CanDirectPkFetch <T>(IQueryable <T> query, CachingOptions options, out string directKey)
        {
            Logger.Log(
                "CanDirectPkFetch with " + query.ToString() + " and " + options.ToLog(),
                Microsoft.Extensions.Logging.LogLevel.Trace
                );

            directKey = null;
            IEntityType entityType = query.GetDbContext().Model.FindEntityType(query.ElementType.FullName);

            // Full Projection
            if (entityType != null)
            {
                IKey             key               = entityType.FindPrimaryKey();
                List <IProperty> primaryKeys       = key.Properties.ToList();
                Dictionary <IProperty, object> pks = new Dictionary <IProperty, object>();
                foreach (IProperty pk in primaryKeys)
                {
                    pks.Add(pk, null);
                }

                List <Expression> queryCriteria = ExtensionMethods.GetQueryCriteriaExp(query.Expression);

                if (queryCriteria.Count == 0)
                {
                    return(false);
                }

                // Verify Entity has PK and query criteria has PK with Equality only
                foreach (Expression exp in queryCriteria)
                {
                    if (!IsExpressionPkEquality(exp, pks))
                    {
                        return(false);
                    }
                }

                // Create Instance then get key
                object instance = Activator.CreateInstance(query.ElementType);
                foreach (var pk in pks)
                {
                    instance.GetType().GetProperty(pk.Key.Name).SetValue(instance, pk.Value);
                }
                // Finally get key
                directKey = QueryCacheManager.Cache.DefaultKeyGen.GetKey(query.GetDbContext(), instance);
                return(true);
            }
            else
            {
                return(false);
            }
        }
Example #4
0
        /// <summary>Static constructor.</summary>
        static QueryCacheManager()
        {
#if EF5 || EF6
            Cache = MemoryCache.Default;
            DefaultCacheItemPolicy = new CacheItemPolicy();
#elif EFCORE
            DefaultNCacheEntryOptions = new CachingOptions();
#endif
            CachePrefix = "NCache;";
            CacheTags   = new ConcurrentDictionary <string, List <string> >();
            IncludeConnectionInCacheKey = false;
            IncludeUserNameAndDatabase  = true;
        }
Example #5
0
        public NCacheEnumerator(string key, IQueryable <T> query, IEnumerable <T> enumerable, CachingOptions options, CacheDependency dbDependency)
        {
            _queryKey        = key;
            _query           = query;
            _innerEnumerable = enumerable;
            _options         = options;
            _dbDependency    = dbDependency;
            _currentContext  = query.GetDbContext();

            _innerEnumerator = _innerEnumerable.GetEnumerator();
            _dataEnumerated  = new Dictionary <string, T>();

            if (_options.StoreAs == StoreAs.SeperateEntities)
            {
                _isSeperateStorageEligible = QueryHelper.IsSeperateStorageEligible(query, options);
            }
        }
Example #6
0
        internal static TItem SetAsCacheEntry <TItem>(this NCacheWrapper cache, object key, TItem value, CachingOptions options, CacheDependency dbDependency)
        {
            Logger.Log(
                "Setting CacheEntry '" + value + "' against key '" + key + "' with DbDependency '" + dbDependency + "'",
                Microsoft.Extensions.Logging.LogLevel.Trace
                );

            CacheEntry entry = cache.CreateEntry(key);

            if (options != null)
            {
                entry.SetOptions(options);
            }
            if (dbDependency != null)
            {
                entry.Dependencies = dbDependency;
            }
            entry.Value = value;

            cache.Set(key, entry, options, dbDependency, options.StoreAs);

            return(value);
        }
Example #7
0
 internal static TItem SetAsCacheEntry <TItem>(this NCacheWrapper cache, object key, TItem value, CachingOptions options)
 {
     return(SetAsCacheEntry(cache, key, value, options, null));
 }
Example #8
0
        // 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;
            }
        }
Example #9
0
 /// <summary>
 /// Checks if the result set is available in cache or not. If it is available it is fetched from the cache and returned
 /// however if it is not available the query is executed on the database and the result set is stored in cache as well
 /// as returned.
 /// </summary>
 /// <typeparam name="T">The generic type of the collection</typeparam>
 /// <param name="query">The query to be executed.</param>
 /// <param name="cacheKey">The key against which the result set will be cached is returned as out parameter.</param>
 /// <param name="options">The option that will be used to store the result set.</param>
 /// <returns>Returns the result set of the query from cache if available else from the database and stores it in 
 /// the cache.
 /// </returns>
 public static IEnumerable<T> FromCache<T>(this IQueryable<T> query, out string cacheKey, CachingOptions options) where T : class
 {
     return FromCacheImplementation(CachingMethod.FromCache, query, out cacheKey, options);
 }
Example #10
0
        internal static TItem[] Set <TItem>(this NCacheWrapper cache, object[] keys, TItem[] values, CachingOptions options, Alachisoft.NCache.Runtime.Dependencies.CacheDependency dbDependency, StoreAs storingAs)
        {
            Logger.Log(
                "Setting items in bulk against respective keys with DbDependency '" + dbDependency + "'.",
                Microsoft.Extensions.Logging.LogLevel.Trace
                );

            Alachisoft.NCache.Web.Caching.CacheItem[] cacheItems = new Alachisoft.NCache.Web.Caching.CacheItem[values.Count()];
            for (int i = 0; i < values.Count(); i++)
            {
                cacheItems[i] = new Alachisoft.NCache.Web.Caching.CacheItem(values[i]);
                CachingOptionsUtil.CopyMetadata(ref cacheItems[i], options, dbDependency);
            }
            if (keys.Length > 0)
            {
                cache.InsertBulk(keys, cacheItems);
            }
            return(values);
        }
Example #11
0
        /// <summary>
        /// Executes the query on the database irrespective of the fact that the result set could have been in the cache
        /// and could have been served from there and updates the result set in the cache.
        /// </summary>
        /// <typeparam name="T">The generic type of the collection</typeparam>
        /// <param name="query">The query to be executed.</param>
        /// <param name="options">The option that will be used to store the result set.</param>
        /// <returns>Returns the result set of the query (encapsulated in a task) after executing it on the databse and storing it in the cache.
        /// </returns>
        public static async Task <IEnumerable <T> > LoadIntoCacheAsync <T>(this IQueryable <T> query, CachingOptions options) where T : class
        {
            Logger.Log(
                "Async operation requested.",
                Microsoft.Extensions.Logging.LogLevel.Trace
                );
            Task <IEnumerable <T> > task = Task.Factory.StartNew(
                () => LoadIntoCache(query, options)
                );

            return(await task);
        }
Example #12
0
 public NCacheEnumerable(string key, IQueryable <T> query, IEnumerable <T> enumerable, CachingOptions options, CacheDependency dbDependency)
 {
     _innerEnumerable   = enumerable;
     _enumeratorWrapper = new NCacheEnumerator <T>(key, query, _innerEnumerable, options, dbDependency);
 }
Example #13
0
        // 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));
            }
        }
Example #14
0
 /// <summary>
 /// Checks if the result is available in cache or not. If it is available it is fetched from the cache and returned
 /// however if it is not available the query is executed on the database and the result is stored in cache as well
 /// as returned.
 /// </summary>
 /// <typeparam name="T">The generic type of the result</typeparam>
 /// <param name="query">The query to be executed.</param>
 /// <param name="cacheKey">The key against which the result will be cached is returned as out parameter.</param>
 /// <param name="options">The option that will be used to store the result.</param>
 /// <returns>Returns the result of the query from cache if available else from the database and stores it in
 /// the cache.
 /// </returns>
 public static T FromCache <T>(this QueryDeferred <T> query, out string cacheKey, CachingOptions options)
 {
     return(FromCacheImplementation(CachingMethod.FromCache, query, out cacheKey, options));
 }
Example #15
0
 /// <summary>
 /// Checks if the result is available in cache or not. If it is available it is fetched from the cache and returned
 /// however if it is not available the query is executed on the database and the result is stored in cache as well
 /// as returned.
 /// </summary>
 /// <typeparam name="T">The generic type of the collection</typeparam>
 /// <param name="query">The query to be executed.</param>
 /// <param name="options">The option that will be used to store the result set.</param>
 /// <returns>Returns the result set of the query from cache if available else from the database and stores it in
 /// the cache.
 /// </returns>
 public static T FromCache <T>(this QueryDeferred <T> query, CachingOptions options)
 {
     return(query.FromCache(out string cacheKey, options));
 }
Example #16
0
        internal static List <TItem> Set <TItem>(this NCacheWrapper cache, object key, Dictionary <string, TItem> value, CachingOptions options, Alachisoft.NCache.Runtime.Dependencies.CacheDependency dbDependency, StoreAs storingAs)
        {
            Logger.Log(
                "About to set values with options " + options.ToLog() + ", DbDependency '" + dbDependency + "' and StoringAs '" + storingAs + "'.",
                Microsoft.Extensions.Logging.LogLevel.Trace
                );

            // Add entities if stroing as seperateEntities
            if (storingAs == StoreAs.SeperateEntities)
            {
                Logger.Log("Values are about to be set as separate entities.", Microsoft.Extensions.Logging.LogLevel.Trace);
                cache.Set(value.Keys.ToArray(), value.Values.ToArray(), options, dbDependency, storingAs);
            }
            // from here onwards is the enumerator logic and now it is being done in "else" after we have moved to tags based result set regeneration
            else
            {
                Logger.Log("Values are about to be set as collection.", Microsoft.Extensions.Logging.LogLevel.Trace);

                // Add query enumerator
                CacheEntry entry = cache.CreateEntry(key);

                // Setting options
                if (options != null)
                {
                    entry.SetOptions(options);
                }

                // Setting Value
                if (storingAs == StoreAs.Collection)
                {
                    entry.Value = value.Values.ToList();
                }

                // Mind that this is not the user specified option but the end storing methodology
                entry.StoredAs = storingAs;

                // Set dependencies in the entry
                var aggregateDependency = new AggregateCacheDependency();
                if (dbDependency != null)
                {
                    aggregateDependency.Add(dbDependency);
                }

                entry.Dependencies = aggregateDependency;

                cache.Set(key, entry, options, dbDependency, storingAs);
            }
            return(value.Values.ToList());
        }
Example #17
0
 internal static TItem Set <TItem>(this NCacheWrapper cache, object key, TItem value, CachingOptions options, Alachisoft.NCache.Runtime.Dependencies.CacheDependency dbDependency, StoreAs storingAs)
 {
     Logger.Log(
         "Setting item '" + value + "' against key '" + key + "' with DbDependency '" + dbDependency + "'.",
         Microsoft.Extensions.Logging.LogLevel.Trace
         );
     Alachisoft.NCache.Web.Caching.CacheItem cacheItem = new Alachisoft.NCache.Web.Caching.CacheItem(value);
     CachingOptionsUtil.CopyMetadata(ref cacheItem, options, dbDependency);
     cache.Insert(key, cacheItem);
     return(value);
 }
Example #18
0
        /// <summary>
        /// Executes the query on the database irrespective of the fact that the result could have been in the cache
        /// and could have been served from there and updates the result in the cache.
        /// </summary>
        /// <typeparam name="T">The generic type of the collection</typeparam>
        /// <param name="query">The query to be executed.</param>
        /// <param name="options">The option that will be used to store the result.</param>
        /// <returns>Returns the result of the query (encapsulated in a task) after executing it on the databse and storing it in the cache.
        /// </returns>
        public static async Task <T> LoadIntoCacheAsync <T>(this QueryDeferred <T> query, CachingOptions options)
        {
            Logger.Log(
                "Async operation requested.",
                Microsoft.Extensions.Logging.LogLevel.Trace
                );
            Task <T> task = Task.Factory.StartNew(
                () => LoadIntoCache(query, options)
                );

            return(await task);
        }
Example #19
0
 /// <summary>
 /// Checks if the result set is available in cache or not. If it is available it is fetched from the cache and returned
 /// however if it is not available the query is executed on the database and the result set is stored in cache as well
 /// as returned.
 /// </summary>
 /// <typeparam name="T">The generic type of the collection</typeparam>
 /// <param name="query">The query to be executed.</param>
 /// <param name="options">The option that will be used to store the result set.</param>
 /// <returns>Returns the result set of the query from cache if available else from the database and stores it in 
 /// the cache.
 /// </returns>
 public static IEnumerable<T> FromCache<T>(this IQueryable<T> query, CachingOptions options) where T : class
 {
     string str;
     return query.FromCache(out str, options);
 }
Example #20
0
        /// <summary>
        /// Executes the query on the database irrespective of the fact that the result set could have been in the cache
        /// and could have been served from there and updates the result set in the cache.
        /// </summary>
        /// <typeparam name="T">The generic type of the collection</typeparam>
        /// <param name="query">The query to be executed.</param>
        /// <param name="options">The option that will be used to store the result set.</param>
        /// <returns>Returns the result set of the query after executing it on the databse and storing it in the cache.
        /// </returns>
        public static IEnumerable <T> LoadIntoCache <T>(this IQueryable <T> query, CachingOptions options) where T : class
        {
            string str;

            return(query.LoadIntoCache(out str, options));
        }