Skip to main content
Rollback to Revision 2
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using ServiceStack.Redis;

namespace Datamodel
{
    public class Repository
    {
        private static readonly PooledRedisClientManager m = new PooledRedisClientManager();

        readonly static IDictionary<Type, List<object>> _cache = new ConcurrentDictionary<Type, List<object>>();

        /// <summary>
        /// Load {T} into object cache from Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        public static void LoadIntoCache<T>() where T : class
        {
            _cache[typeof(T)] = RedisGetAll<T>().Cast<object>().ToList();
        }

        /// <summary>
        /// Add single {T} into cache and Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="entity">class object</param>
        public static void Create<T>(T entity) where T : class
        {
            // Lets prevent race conditions, locking down cache.
            lock (_cache[typeof(T)])
            {
                List<object> list;
                if (!_cache.TryGetValue(typeof(T), out list))
                {
                    list = new List<object>();
                }
                list.Add(entity);
                _cache[typeof(T)] = list;
                RedisStore<T>(entity);
            }
        }

        /// <summary>
        /// Find First {T} in object cache.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq statement</param>
        /// <returns></returns>
        public static T FindFirstBy<T>(Func<T, bool> predicate) where T : class
        {
            // Lets prevent race conditions, locking down cache.
            lock (_cache[typeof(T)])
            {
                List<object> list;
                if (_cache.TryGetValue(typeof(T), out list))
                {
                   = returnnew list.Cast<T>().Where(predicate).FirstOrDefaultList<object>();
                }
                return null;
            }
            list.Add(entity);
            _cache[typeof(T)] = list;
            RedisStore<T>(entity);
        }

        /// <summary>
        /// Find Single {T} in object cache.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq statement</param>
        /// <returns></returns>
        public static T FindSingleBy<T>Read<T>(Func<T, bool> predicate) where T : class
        {
            // Lets prevent race conditions, locking downList<object> cache.list;
            lockif (_cache[typeof_cache.TryGetValue(typeof(T)], out list))
            {
                List<object> list;
                if (_cache.TryGetValue(typeof(T), out list))
                {
                    return list.Cast<T>().Where(predicate).SingleOrDefaultFirstOrDefault();
                }
                return null;
            }
            return null;
        }

        /// <summary>
        /// Tries to update or Add entity to object cache and Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq expression</param>
        /// <param name="entity">entity</param>
        public static boolvoid AddOrUpdate<T>Update<T>(Func<T, bool> predicate, T entity) where T : class
        {
            // Lets prevent race conditions, locking downList<object> cache.list;
            lockif (_cache[typeof_cache.TryGetValue(typeof(T)], out list))
            {
                // Find Type cache.
                List<object> list;
                if (!_cache.TryGetValue(typeof(T), out list))
                {
                    // Incase this tpye was not pre-loaded into cache we will cache new entities from here on out.
                    list = new List<object>();
                }

                // Look for old entity.
                var e = list.Cast<T>().Where(predicate).FirstOrDefault();

                // If no old record exists no problem we treat this as if its a new record.
                if (e != null)
                {
                    // Old record found removing it.
                    list.Remove(e);
                }

                // Regardless if object existed or not we add it to our Cache / Data Store.
                list.Add(entity);
                _cache[typeof(T)] = list;
                RedisStore<T>(entity);
            }

            // Redis does not care if record is new or old as it will Add or Update regardless.
            RedisStore<T>(entity);

            return true;
        }

        /// <summary>
        /// Delete single {T} from cache and Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="entity">class object</param>
        public static void Remove<T>Delete<T>(T entity) where T : class
        {
            // Lets prevent race conditions, locking downList<object> cache.list;
            lockif (_cache[typeof_cache.TryGetValue(typeof(T)], out list))
            {
                List<object> list;
                if (_cache.TryGetValue(typeof(T), out list))
                {
                    list.Remove(entity);
                    _cache[typeof(T)] = list;

                    RedisDelete<T>(entity);
                }
            }
        }

        /// <summary>
        /// Find List<T>(predicate) in cache.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq statement</param>
        /// <returns></returns>
        public static List<T> FindBy<T>(Func<T, bool> predicate) where T : class
        {
            // Lets prevent race conditions, locking downList<object> cache.list;
            lockif (_cache[typeof_cache.TryGetValue(typeof(T)], out list))
            {
                List<object> list;
                if (_cache.TryGetValue(typeof(T), out list))
                {
                    return list.Cast<T>().Where(predicate).ToList();
                }
                return new List<T>();
            }
            return new List<T>();
        }

        /// <summary>
        /// Get Next Sequence for theFind gienAll {T} Entity from Data Store. 
        /// </summary>
        /// <typeparam name="T">class<name="T"></typeparam>
        /// <returns>long<<returns>List<T></returns>
        public static longList<T> Next<T>All<T>() where T : class
        {
            return RedisNext<T>RedisGetAll<T>().ToList();
        }

        #region Redis Commands
        //
        // Following methods are ment as static private methods.
        //

        private static List<T> All<T>() where T : class
        {
            return RedisGetAll<T>().ToList();
        }

        privatepublic static long RedisNext<T>Next<T>() where T : class
        {
            using (var ctx = m.GetClient())
                return ctx.As<T>().GetNextSequence();
        }

        private static void RedisDelete<T>(T entity) where T : class
        {
            using (var ctx = m.GetClient())
                ctx.As<T>().Delete(entity);
        }

        private static T RedisFind<T>(long id) where T : class
        {
            using (var ctx = m.GetClient())
                return ctx.As<T>().GetById(id);
        }

        private static IList<T> RedisGetAll<T>() where T : class
        {
            using (var ctx = m.GetClient())
                return ctx.As<T>().GetAll();
        }

        private static void RedisStore<T>(T entity) where T : class
        {
            using (var ctx = m.GetClient())
                ctx.Store<T>(entity);
        }

        #endregion
    }

    /// <summary>
    /// Simple Test Entity
    /// </summary>
    public class User
    {
        public User()
        {
            Id = Repository.Next<User>();
        }

        public long Id { get; private set; }
        public string Name { get; set; }
    }
 
}
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using ServiceStack.Redis;

namespace Datamodel
{
    public class Repository
    {
        private static readonly PooledRedisClientManager m = new PooledRedisClientManager();

        readonly static IDictionary<Type, List<object>> _cache = new ConcurrentDictionary<Type, List<object>>();

        /// <summary>
        /// Load {T} into object cache from Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        public static void LoadIntoCache<T>() where T : class
        {
            _cache[typeof(T)] = RedisGetAll<T>().Cast<object>().ToList();
        }

        /// <summary>
        /// Add single {T} into cache and Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="entity">class object</param>
        public static void Create<T>(T entity) where T : class
        {
            // Lets prevent race conditions, locking down cache.
            lock (_cache[typeof(T)])
            {
                List<object> list;
                if (!_cache.TryGetValue(typeof(T), out list))
                {
                    list = new List<object>();
                }
                list.Add(entity);
                _cache[typeof(T)] = list;
                RedisStore<T>(entity);
            }
        }

        /// <summary>
        /// Find First {T} in object cache.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq statement</param>
        /// <returns></returns>
        public static T FindFirstBy<T>(Func<T, bool> predicate) where T : class
        {
            // Lets prevent race conditions, locking down cache.
            lock (_cache[typeof(T)])
            {
                List<object> list;
                if (_cache.TryGetValue(typeof(T), out list))
                {
                    return list.Cast<T>().Where(predicate).FirstOrDefault();
                }
                return null;
            }
        }

        /// <summary>
        /// Find Single {T} in object cache.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq statement</param>
        /// <returns></returns>
        public static T FindSingleBy<T>(Func<T, bool> predicate) where T : class
        {
            // Lets prevent race conditions, locking down cache.
            lock (_cache[typeof(T)])
            {
                List<object> list;
                if (_cache.TryGetValue(typeof(T), out list))
                {
                    return list.Cast<T>().Where(predicate).SingleOrDefault();
                }
                return null;
            }
        }

        /// <summary>
        /// Tries to update or Add entity to object cache and Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq expression</param>
        /// <param name="entity">entity</param>
        public static bool AddOrUpdate<T>(Func<T, bool> predicate, T entity) where T : class
        {
            // Lets prevent race conditions, locking down cache.
            lock (_cache[typeof(T)])
            {
                // Find Type cache.
                List<object> list;
                if (!_cache.TryGetValue(typeof(T), out list))
                {
                    // Incase this tpye was not pre-loaded into cache we will cache new entities from here on out.
                    list = new List<object>();
                }

                // Look for old entity.
                var e = list.Cast<T>().Where(predicate).FirstOrDefault();

                // If no old record exists no problem we treat this as if its a new record.
                if (e != null)
                {
                    // Old record found removing it.
                    list.Remove(e);
                }

                // Regardless if object existed or not we add it to our Cache / Data Store.
                list.Add(entity);
                _cache[typeof(T)] = list;
            }

            // Redis does not care if record is new or old as it will Add or Update regardless.
            RedisStore<T>(entity);

            return true;
        }

        /// <summary>
        /// Delete single {T} from cache and Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="entity">class object</param>
        public static void Remove<T>(T entity) where T : class
        {
            // Lets prevent race conditions, locking down cache.
            lock (_cache[typeof(T)])
            {
                List<object> list;
                if (_cache.TryGetValue(typeof(T), out list))
                {
                    list.Remove(entity);
                    _cache[typeof(T)] = list;

                    RedisDelete<T>(entity);
                }
            }
        }

        /// <summary>
        /// Find List<T>(predicate) in cache.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq statement</param>
        /// <returns></returns>
        public static List<T> FindBy<T>(Func<T, bool> predicate) where T : class
        {
            // Lets prevent race conditions, locking down cache.
            lock (_cache[typeof(T)])
            {
                List<object> list;
                if (_cache.TryGetValue(typeof(T), out list))
                {
                    return list.Cast<T>().Where(predicate).ToList();
                }
                return new List<T>();
            }
        }

        /// <summary>
        /// Get Next Sequence for the gien {T} Entity from Data Store. 
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <returns>long</returns>
        public static long Next<T>() where T : class
        {
            return RedisNext<T>();
        }

        #region Redis Commands
        //
        // Following methods are ment as static private methods.
        //

        private static List<T> All<T>() where T : class
        {
            return RedisGetAll<T>().ToList();
        }

        private static long RedisNext<T>() where T : class
        {
            using (var ctx = m.GetClient())
                return ctx.As<T>().GetNextSequence();
        }

        private static void RedisDelete<T>(T entity) where T : class
        {
            using (var ctx = m.GetClient())
                ctx.As<T>().Delete(entity);
        }

        private static T RedisFind<T>(long id) where T : class
        {
            using (var ctx = m.GetClient())
                return ctx.As<T>().GetById(id);
        }

        private static IList<T> RedisGetAll<T>() where T : class
        {
            using (var ctx = m.GetClient())
                return ctx.As<T>().GetAll();
        }

        private static void RedisStore<T>(T entity) where T : class
        {
            using (var ctx = m.GetClient())
                ctx.Store<T>(entity);
        }

        #endregion
    }
}
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using ServiceStack.Redis;

namespace Datamodel
{
    public class Repository
    {
        private static readonly PooledRedisClientManager m = new PooledRedisClientManager();

        readonly static IDictionary<Type, List<object>> _cache = new ConcurrentDictionary<Type, List<object>>();

        /// <summary>
        /// Load {T} into object cache from Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        public static void LoadIntoCache<T>() where T : class
        {
            _cache[typeof(T)] = RedisGetAll<T>().Cast<object>().ToList();
        }

        /// <summary>
        /// Add single {T} into cache and Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="entity">class object</param>
        public static void Create<T>(T entity) where T : class
        {
            List<object> list;
            if (!_cache.TryGetValue(typeof(T), out list))
            {
                list = new List<object>();
            }
            list.Add(entity);
            _cache[typeof(T)] = list;
            RedisStore<T>(entity);
        }

        /// <summary>
        /// Find Single {T} in object cache.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq statement</param>
        /// <returns></returns>
        public static T Read<T>(Func<T, bool> predicate) where T : class
        {
            List<object> list;
            if (_cache.TryGetValue(typeof(T), out list))
            {
                return list.Cast<T>().Where(predicate).FirstOrDefault();
            }
            return null;
        }

        /// <summary>
        /// Tries to update or Add entity to object cache and Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq expression</param>
        /// <param name="entity">entity</param>
        public static void Update<T>(Func<T, bool> predicate, T entity) where T : class
        {
            List<object> list;
            if (_cache.TryGetValue(typeof(T), out list))
            {
                // Look for old entity.
                var e = list.Cast<T>().Where(predicate).FirstOrDefault();

                if (e != null)
                {
                    list.Remove(e);
                }

                // Regardless if object existed or not we add it to our Cache / Data Store.
                list.Add(entity);
                _cache[typeof(T)] = list;
                RedisStore<T>(entity);
            }
        }

        /// <summary>
        /// Delete single {T} from cache and Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="entity">class object</param>
        public static void Delete<T>(T entity) where T : class
        {
            List<object> list;
            if (_cache.TryGetValue(typeof(T), out list))
            {
                list.Remove(entity);
                _cache[typeof(T)] = list;

                RedisDelete<T>(entity);
            }
        }

        /// <summary>
        /// Find List<T>(predicate) in cache.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq statement</param>
        /// <returns></returns>
        public static List<T> FindBy<T>(Func<T, bool> predicate) where T : class
        {
            List<object> list;
            if (_cache.TryGetValue(typeof(T), out list))
            {
                return list.Cast<T>().Where(predicate).ToList();
            }
            return new List<T>();
        }

        /// <summary>
        /// Find All {T}
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns>List<T></returns>
        public static List<T> All<T>() where T : class
        {
            return RedisGetAll<T>().ToList();
        }

        #region Redis Commands

        public static long Next<T>() where T : class
        {
            using (var ctx = m.GetClient())
                return ctx.As<T>().GetNextSequence();
        }

        private static void RedisDelete<T>(T entity) where T : class
        {
            using (var ctx = m.GetClient())
                ctx.As<T>().Delete(entity);
        }

        private static T RedisFind<T>(long id) where T : class
        {
            using (var ctx = m.GetClient())
                return ctx.As<T>().GetById(id);
        }

        private static IList<T> RedisGetAll<T>() where T : class
        {
            using (var ctx = m.GetClient())
                return ctx.As<T>().GetAll();
        }

        private static void RedisStore<T>(T entity) where T : class
        {
            using (var ctx = m.GetClient())
                ctx.Store<T>(entity);
        }

        #endregion
    }

    /// <summary>
    /// Simple Test Entity
    /// </summary>
    public class User
    {
        public User()
        {
            Id = Repository.Next<User>();
        }

        public long Id { get; private set; }
        public string Name { get; set; }
    }
 
}
Updated with locks, renamed Update to AddOrUpdate to reflect its actual function. Valid lock?
Source Link
Joachim
  • 205
  • 3
  • 11
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using ServiceStack.Redis;

namespace Datamodel
{
    public class Repository
    {
        private static readonly PooledRedisClientManager m = new PooledRedisClientManager();

        readonly static IDictionary<Type, List<object>> _cache = new ConcurrentDictionary<Type, List<object>>();

        /// <summary>
        /// Load {T} into object cache from Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        public static void LoadIntoCache<T>() where T : class
        {
            _cache[typeof(T)] = RedisGetAll<T>().Cast<object>().ToList();
        }

        /// <summary>
        /// Add single {T} into cache and Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="entity">class object</param>
        public static void Create<T>(T entity) where T : class
        {
            List<object>// list;Lets prevent race conditions, locking down cache.
            iflock (!_cache.TryGetValue(typeof_cache[typeof(T), out list)])
            {
                List<object> list;
                if (!_cache.TryGetValue(typeof(T), out list))
                {
                    list = new List<object>();
                }
                list.Add(entity);
                _cache[typeof(T)] = list;
                RedisStore<T>(entity);
            }
        }

    list    /// <summary>
        /// Find First {T} in object cache.Add
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq statement</param>
        /// <returns></returns>
        public static T FindFirstBy<T>(entityFunc<T, bool> predicate); where T : class
        {
            // Lets prevent race conditions, locking down cache.
            lock (_cache[typeof(T)])
 =           {
                List<object> list;
            RedisStore<T>    if (entity_cache.TryGetValue(typeof(T), out list))
                {
                    return list.Cast<T>().Where(predicate).FirstOrDefault();
                }
                return null;
            }
        }

        /// <summary>
        /// Find Single {T} in object cache.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq statement</param>
        /// <returns></returns>
        public static T Read<T>FindSingleBy<T>(Func<T, bool> predicate) where T : class
        {
            List<object>// list;Lets prevent race conditions, locking down cache.
            iflock (_cache.TryGetValue(typeof_cache[typeof(T), out list)])
            {
                List<object> list;
                if (_cache.TryGetValue(typeof(T), out list))
                {
                    return list.Cast<T>().Where(predicate).FirstOrDefaultSingleOrDefault();
                }
                return null;
            }
            return null;
        }

        /// <summary>
        /// Tries to update or Add entity to object cache and Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq expression</param>
        /// <param name="entity">entity</param>
        public static voidbool Update<T>AddOrUpdate<T>(Func<T, bool> predicate, T entity) where T : class
        {
            List<object>// list;Lets prevent race conditions, locking down cache.
            iflock (_cache.TryGetValue(typeof_cache[typeof(T), out list)])
            {
                // Find Type cache.
                List<object> list;
                if (!_cache.TryGetValue(typeof(T), out list))
                {
                    // Incase this tpye was not pre-loaded into cache we will cache new entities from here on out.
                    list = new List<object>();
                }

                // Look for old entity.
                var e = list.Cast<T>().Where(predicate).FirstOrDefault();

                // If no old record exists no problem we treat this as if its a new record.
                if (e != null)
                {
                    // Old record found removing it.
                    list.Remove(e);
                }

                // Regardless if object existed or not we add it to our Cache / Data Store.
                list.Add(entity);
                _cache[typeof(T)] = list;
                RedisStore<T>(entity);
            }

            // Redis does not care if record is new or old as it will Add or Update regardless.
            RedisStore<T>(entity);

            return true;
        }

        /// <summary>
        /// Delete single {T} from cache and Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="entity">class object</param>
        public static void Delete<T>Remove<T>(T entity) where T : class
        {
            List<object>// list;Lets prevent race conditions, locking down cache.
            iflock (_cache.TryGetValue(typeof_cache[typeof(T), out list)])
            {
                List<object> list;
                if (_cache.TryGetValue(typeof(T), out list))
                {
                    list.Remove(entity);
                    _cache[typeof(T)] = list;

                    RedisDelete<T>(entity);
                }
            }
        }

        /// <summary>
        /// Find List<T>(predicate) in cache.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq statement</param>
        /// <returns></returns>
        public static List<T> FindBy<T>(Func<T, bool> predicate) where T : class
        {
            List<object>// list;Lets prevent race conditions, locking down cache.
            iflock (_cache.TryGetValue(typeof_cache[typeof(T), out list)])
            {
                List<object> list;
                if (_cache.TryGetValue(typeof(T), out list))
                {
                    return list.Cast<T>().Where(predicate).ToList();
                }
                return new List<T>();
            }
            return new List<T>();
        }

        /// <summary>
        /// FindGet AllNext Sequence for the gien {T} Entity from Data Store. 
        /// </summary>
        /// <typeparam name="T"><name="T">class</typeparam>
        /// <returns>List<T><<returns>long</returns>
        public static List<T>long All<T>Next<T>() where T : class
        {
            return RedisGetAll<T>().ToListRedisNext<T>();
        }

        #region Redis Commands
        //
        // Following methods are ment as static private methods.
        //

        publicprivate static longList<T> Next<T>All<T>() where T : class
        {
            return RedisGetAll<T>().ToList();
        }

        private static long RedisNext<T>() where T : class
        {
            using (var ctx = m.GetClient())
                return ctx.As<T>().GetNextSequence();
        }

        private static void RedisDelete<T>(T entity) where T : class
        {
            using (var ctx = m.GetClient())
                ctx.As<T>().Delete(entity);
        }

        private static T RedisFind<T>(long id) where T : class
        {
            using (var ctx = m.GetClient())
                return ctx.As<T>().GetById(id);
        }

        private static IList<T> RedisGetAll<T>() where T : class
        {
            using (var ctx = m.GetClient())
                return ctx.As<T>().GetAll();
        }

        private static void RedisStore<T>(T entity) where T : class
        {
            using (var ctx = m.GetClient())
                ctx.Store<T>(entity);
        }

        #endregion
    }

    /// <summary>
    /// Simple Test Entity
    /// </summary>
    public class User
    {
        public User()
        {
            Id = Repository.Next<User>();
        }

        public long Id { get; private set; }
        public string Name { get; set; }
    }

 }
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using ServiceStack.Redis;

namespace Datamodel
{
    public class Repository
    {
        private static readonly PooledRedisClientManager m = new PooledRedisClientManager();

        readonly static IDictionary<Type, List<object>> _cache = new ConcurrentDictionary<Type, List<object>>();

        /// <summary>
        /// Load {T} into object cache from Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        public static void LoadIntoCache<T>() where T : class
        {
            _cache[typeof(T)] = RedisGetAll<T>().Cast<object>().ToList();
        }

        /// <summary>
        /// Add single {T} into cache and Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="entity">class object</param>
        public static void Create<T>(T entity) where T : class
        {
            List<object> list;
            if (!_cache.TryGetValue(typeof(T), out list))
            {
                list = new List<object>();
            }
            list.Add(entity);
            _cache[typeof(T)] = list;
            RedisStore<T>(entity);
        }

        /// <summary>
        /// Find Single {T} in object cache.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq statement</param>
        /// <returns></returns>
        public static T Read<T>(Func<T, bool> predicate) where T : class
        {
            List<object> list;
            if (_cache.TryGetValue(typeof(T), out list))
            {
                return list.Cast<T>().Where(predicate).FirstOrDefault();
            }
            return null;
        }

        /// <summary>
        /// Tries to update or Add entity to object cache and Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq expression</param>
        /// <param name="entity">entity</param>
        public static void Update<T>(Func<T, bool> predicate, T entity) where T : class
        {
            List<object> list;
            if (_cache.TryGetValue(typeof(T), out list))
            {
                // Look for old entity.
                var e = list.Cast<T>().Where(predicate).FirstOrDefault();

                if (e != null)
                {
                    list.Remove(e);
                }

                // Regardless if object existed or not we add it to our Cache / Data Store.
                list.Add(entity);
                _cache[typeof(T)] = list;
                RedisStore<T>(entity);
            }
        }

        /// <summary>
        /// Delete single {T} from cache and Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="entity">class object</param>
        public static void Delete<T>(T entity) where T : class
        {
            List<object> list;
            if (_cache.TryGetValue(typeof(T), out list))
            {
                list.Remove(entity);
                _cache[typeof(T)] = list;

                RedisDelete<T>(entity);
            }
        }

        /// <summary>
        /// Find List<T>(predicate) in cache.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq statement</param>
        /// <returns></returns>
        public static List<T> FindBy<T>(Func<T, bool> predicate) where T : class
        {
            List<object> list;
            if (_cache.TryGetValue(typeof(T), out list))
            {
                return list.Cast<T>().Where(predicate).ToList();
            }
            return new List<T>();
        }

        /// <summary>
        /// Find All {T}
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns>List<T></returns>
        public static List<T> All<T>() where T : class
        {
            return RedisGetAll<T>().ToList();
        }

        #region Redis Commands

        public static long Next<T>() where T : class
        {
            using (var ctx = m.GetClient())
                return ctx.As<T>().GetNextSequence();
        }

        private static void RedisDelete<T>(T entity) where T : class
        {
            using (var ctx = m.GetClient())
                ctx.As<T>().Delete(entity);
        }

        private static T RedisFind<T>(long id) where T : class
        {
            using (var ctx = m.GetClient())
                return ctx.As<T>().GetById(id);
        }

        private static IList<T> RedisGetAll<T>() where T : class
        {
            using (var ctx = m.GetClient())
                return ctx.As<T>().GetAll();
        }

        private static void RedisStore<T>(T entity) where T : class
        {
            using (var ctx = m.GetClient())
                ctx.Store<T>(entity);
        }

        #endregion
    }

    /// <summary>
    /// Simple Test Entity
    /// </summary>
    public class User
    {
        public User()
        {
            Id = Repository.Next<User>();
        }

        public long Id { get; private set; }
        public string Name { get; set; }
    }

 }
using System;
using System.Collections.Generic;
using System.Collections.Concurrent;
using System.Linq;
using ServiceStack.Redis;

namespace Datamodel
{
    public class Repository
    {
        private static readonly PooledRedisClientManager m = new PooledRedisClientManager();

        readonly static IDictionary<Type, List<object>> _cache = new ConcurrentDictionary<Type, List<object>>();

        /// <summary>
        /// Load {T} into object cache from Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        public static void LoadIntoCache<T>() where T : class
        {
            _cache[typeof(T)] = RedisGetAll<T>().Cast<object>().ToList();
        }

        /// <summary>
        /// Add single {T} into cache and Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="entity">class object</param>
        public static void Create<T>(T entity) where T : class
        {
            // Lets prevent race conditions, locking down cache.
            lock (_cache[typeof(T)])
            {
                List<object> list;
                if (!_cache.TryGetValue(typeof(T), out list))
                {
                    list = new List<object>();
                }
                list.Add(entity);
                _cache[typeof(T)] = list;
                RedisStore<T>(entity);
            }
        }

        /// <summary>
        /// Find First {T} in object cache.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq statement</param>
        /// <returns></returns>
        public static T FindFirstBy<T>(Func<T, bool> predicate) where T : class
        {
            // Lets prevent race conditions, locking down cache.
            lock (_cache[typeof(T)])
            {
                List<object> list;
                if (_cache.TryGetValue(typeof(T), out list))
                {
                    return list.Cast<T>().Where(predicate).FirstOrDefault();
                }
                return null;
            }
        }

        /// <summary>
        /// Find Single {T} in object cache.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq statement</param>
        /// <returns></returns>
        public static T FindSingleBy<T>(Func<T, bool> predicate) where T : class
        {
            // Lets prevent race conditions, locking down cache.
            lock (_cache[typeof(T)])
            {
                List<object> list;
                if (_cache.TryGetValue(typeof(T), out list))
                {
                    return list.Cast<T>().Where(predicate).SingleOrDefault();
                }
                return null;
            }
        }

        /// <summary>
        /// Tries to update or Add entity to object cache and Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq expression</param>
        /// <param name="entity">entity</param>
        public static bool AddOrUpdate<T>(Func<T, bool> predicate, T entity) where T : class
        {
            // Lets prevent race conditions, locking down cache.
            lock (_cache[typeof(T)])
            {
                // Find Type cache.
                List<object> list;
                if (!_cache.TryGetValue(typeof(T), out list))
                {
                    // Incase this tpye was not pre-loaded into cache we will cache new entities from here on out.
                    list = new List<object>();
                }

                // Look for old entity.
                var e = list.Cast<T>().Where(predicate).FirstOrDefault();

                // If no old record exists no problem we treat this as if its a new record.
                if (e != null)
                {
                    // Old record found removing it.
                    list.Remove(e);
                }

                // Regardless if object existed or not we add it to our Cache / Data Store.
                list.Add(entity);
                _cache[typeof(T)] = list;
            }

            // Redis does not care if record is new or old as it will Add or Update regardless.
            RedisStore<T>(entity);

            return true;
        }

        /// <summary>
        /// Delete single {T} from cache and Data Store.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="entity">class object</param>
        public static void Remove<T>(T entity) where T : class
        {
            // Lets prevent race conditions, locking down cache.
            lock (_cache[typeof(T)])
            {
                List<object> list;
                if (_cache.TryGetValue(typeof(T), out list))
                {
                    list.Remove(entity);
                    _cache[typeof(T)] = list;

                    RedisDelete<T>(entity);
                }
            }
        }

        /// <summary>
        /// Find List<T>(predicate) in cache.
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <param name="predicate">linq statement</param>
        /// <returns></returns>
        public static List<T> FindBy<T>(Func<T, bool> predicate) where T : class
        {
            // Lets prevent race conditions, locking down cache.
            lock (_cache[typeof(T)])
            {
                List<object> list;
                if (_cache.TryGetValue(typeof(T), out list))
                {
                    return list.Cast<T>().Where(predicate).ToList();
                }
                return new List<T>();
            }
        }

        /// <summary>
        /// Get Next Sequence for the gien {T} Entity from Data Store. 
        /// </summary>
        /// <typeparam name="T">class</typeparam>
        /// <returns>long</returns>
        public static long Next<T>() where T : class
        {
            return RedisNext<T>();
        }

        #region Redis Commands
        //
        // Following methods are ment as static private methods.
        //

        private static List<T> All<T>() where T : class
        {
            return RedisGetAll<T>().ToList();
        }

        private static long RedisNext<T>() where T : class
        {
            using (var ctx = m.GetClient())
                return ctx.As<T>().GetNextSequence();
        }

        private static void RedisDelete<T>(T entity) where T : class
        {
            using (var ctx = m.GetClient())
                ctx.As<T>().Delete(entity);
        }

        private static T RedisFind<T>(long id) where T : class
        {
            using (var ctx = m.GetClient())
                return ctx.As<T>().GetById(id);
        }

        private static IList<T> RedisGetAll<T>() where T : class
        {
            using (var ctx = m.GetClient())
                return ctx.As<T>().GetAll();
        }

        private static void RedisStore<T>(T entity) where T : class
        {
            using (var ctx = m.GetClient())
                ctx.Store<T>(entity);
        }

        #endregion
    }
}
deleted 3 characters in body
Source Link
Jamal
  • 35.2k
  • 13
  • 134
  • 238

Hi I have written a Cached-Object store with a Redis Client for persistent storage, the. The application that is going to use this is a heavy read application with the occasional write,. I assume that entire model will contain somewhere around 500k - 1m entities, the. The tests I have done so far with a far more complicated model than I include as example shows that Entity Framework does not come close performance wise. Now that said I am curious if I have made any fatal mistakes in my Repository code.

Hi I have written a Cached-Object store with a Redis Client for persistent storage, the application that is going to use this is a heavy read application with the occasional write, I assume that entire model will contain somewhere around 500k - 1m entities, the tests I have done so far with a far more complicated model than I include as example shows that Entity Framework does not come close performance wise. Now that said I am curious if I have made any fatal mistakes in my Repository code.

I have written a Cached-Object store with a Redis Client for persistent storage. The application that is going to use this is a heavy read application with the occasional write. I assume that entire model will contain somewhere around 500k - 1m entities. The tests I have done so far with a far more complicated model than I include as example shows that Entity Framework does not come close performance wise. Now that said I am curious if I have made any fatal mistakes in my Repository code.

Source Link
Joachim
  • 205
  • 3
  • 11
Loading