Beispiel #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");
            }
        }
Beispiel #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);
            }
        }
Beispiel #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);
            }
        }
Beispiel #4
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());
        }
Beispiel #5
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;
            }
        }
Beispiel #6
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));
            }
        }