How to store list element in Redis cache How to store list element in Redis cache azure azure

How to store list element in Redis cache


If you use Stackechange.Redis, you can use the List methods on its API.Here is a naive implementation of IList using a redis list to store the items.

Hopefully it can help you to understand some of the list API methods:

public class RedisList<T> : IList<T>{    private static ConnectionMultiplexer _cnn;    private string key;    public RedisList(string key)    {        this.key = key;        _cnn = ConnectionMultiplexer.Connect("localhost");    }    private IDatabase GetRedisDb()    {        return _cnn.GetDatabase();    }    private string Serialize(object obj)    {        return JsonConvert.SerializeObject(obj);    }    private T Deserialize<T>(string serialized)    {        return JsonConvert.DeserializeObject<T>(serialized);    }    public void Insert(int index, T item)    {        var db = GetRedisDb();        var before = db.ListGetByIndex(key, index);        db.ListInsertBefore(key, before, Serialize(item));    }    public void RemoveAt(int index)    {        var db = GetRedisDb();        var value = db.ListGetByIndex(key, index);        if (!value.IsNull)        {            db.ListRemove(key, value);        }    }    public T this[int index]    {        get        {            var value = GetRedisDb().ListGetByIndex(key, index);            return Deserialize<T>(value.ToString());        }        set        {            Insert(index, value);        }    }    public void Add(T item)    {        GetRedisDb().ListRightPush(key, Serialize(item));    }    public void Clear()    {        GetRedisDb().KeyDelete(key);    }    public bool Contains(T item)    {        for (int i = 0; i < Count; i++)        {            if (GetRedisDb().ListGetByIndex(key, i).ToString().Equals(Serialize(item)))            {                return true;            }        }        return false;    }    public void CopyTo(T[] array, int arrayIndex)    {        GetRedisDb().ListRange(key).CopyTo(array, arrayIndex);    }    public int IndexOf(T item)    {        for (int i = 0; i < Count; i++)        {            if (GetRedisDb().ListGetByIndex(key, i).ToString().Equals(Serialize(item)))            {                return i;            }        }        return -1;    }    public int Count    {        get { return (int)GetRedisDb().ListLength(key); }    }    public bool IsReadOnly    {        get { return false; }    }    public bool Remove(T item)    {        return GetRedisDb().ListRemove(key, Serialize(item)) > 0;    }    public IEnumerator<T> GetEnumerator()    {        for (int i = 0; i < this.Count; i++)        {            yield return Deserialize<T>(GetRedisDb().ListGetByIndex(key, i).ToString());        }    }    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()    {        for (int i = 0; i < this.Count; i++)        {            yield return Deserialize<T>(GetRedisDb().ListGetByIndex(key, i).ToString());        }    }}

Note the use of Newtonsoft.Json for the serialization.You will need the following nu-get packages:

Install-Package Newtonsoft.JsonInstall-Package StackExchange.Redis

After reading your question and comments, since you want to access elements by key, I think you're looking for Redis Hashes, which are maps composed of fields associated with values.

So you can have a Redis Key for a Hash containing all your Customers, each one being a Value associated to a Field. You can choose the CustomerId as the Field, so you can then get a customer by its id in O(1).

I think implementing IDictionary is a good way to see it working.So a RedisDictionary class similar to the RedisList but using a Redis Hash could be:

public class RedisDictionary<TKey, TValue> : IDictionary<TKey, TValue>{    private static ConnectionMultiplexer _cnn;    private string _redisKey;    public RedisDictionary(string redisKey)    {        _redisKey = redisKey;        _cnn = ConnectionMultiplexer.Connect("localhost");    }    private IDatabase GetRedisDb()    {        return _cnn.GetDatabase();    }    private string Serialize(object obj)    {        return JsonConvert.SerializeObject(obj);    }    private T Deserialize<T>(string serialized)    {        return JsonConvert.DeserializeObject<T>(serialized);    }    public void Add(TKey key, TValue value)    {        GetRedisDb().HashSet(_redisKey, Serialize(key), Serialize(value));    }    public bool ContainsKey(TKey key)    {        return GetRedisDb().HashExists(_redisKey, Serialize(key));    }    public bool Remove(TKey key)    {        return GetRedisDb().HashDelete(_redisKey, Serialize(key));    }    public bool TryGetValue(TKey key, out TValue value)    {        var redisValue = GetRedisDb().HashGet(_redisKey, Serialize(key));        if (redisValue.IsNull)        {            value = default(TValue);            return false;        }        value = Deserialize<TValue>(redisValue.ToString());        return true;    }    public ICollection<TValue> Values    {        get { return new Collection<TValue>(GetRedisDb().HashValues(_redisKey).Select(h => Deserialize<TValue>(h.ToString())).ToList()); }    }    public ICollection<TKey> Keys    {        get { return new Collection<TKey>(GetRedisDb().HashKeys(_redisKey).Select(h => Deserialize<TKey>(h.ToString())).ToList()); }    }    public TValue this[TKey key]    {        get        {            var redisValue = GetRedisDb().HashGet(_redisKey, Serialize(key));            return redisValue.IsNull ? default(TValue) : Deserialize<TValue>(redisValue.ToString());        }        set        {            Add(key, value);        }    }    public void Add(KeyValuePair<TKey, TValue> item)    {        Add(item.Key, item.Value);    }    public void Clear()    {        GetRedisDb().KeyDelete(_redisKey);    }    public bool Contains(KeyValuePair<TKey, TValue> item)    {        return GetRedisDb().HashExists(_redisKey, Serialize(item.Key));    }    public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)    {        GetRedisDb().HashGetAll(_redisKey).CopyTo(array, arrayIndex);    }    public int Count    {        get { return (int)GetRedisDb().HashLength(_redisKey); }    }    public bool IsReadOnly    {        get { return false; }    }    public bool Remove(KeyValuePair<TKey, TValue> item)    {        return Remove(item.Key);    }    public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()    {        var db = GetRedisDb();        foreach (var hashKey in db.HashKeys(_redisKey))        {            var redisValue = db.HashGet(_redisKey, hashKey);            yield return new KeyValuePair<TKey, TValue>(Deserialize<TKey>(hashKey.ToString()), Deserialize<TValue>(redisValue.ToString()));        }    }    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()    {        yield return GetEnumerator();    }    public void AddMultiple(IEnumerable<KeyValuePair<TKey, TValue>> items)    {        GetRedisDb()            .HashSet(_redisKey, items.Select(i => new HashEntry(Serialize(i.Key), Serialize(i.Value))).ToArray());    }}

And here are some examples to use it:

// Insert customers to the cache            var customers = new RedisDictionary<int, Customer>("customers");customers.Add(100, new Customer() { Id = 100, Name = "John" });customers.Add(200, new Customer() { Id = 200, Name = "Peter" });// Or if you have a list of customers retrieved from DB:IList<Customer> customerListFromDb;customers.AddMultiple(customerListFromDb.ToDictionary(k => k.Id));// Query a customer by its idvar customers = new RedisDictionary<int, Customer>("customers");Customer customer100 = customers[100];

Update (Oct 2015)

A better implementation of these collections can be found on CachingFramework.Redis library.

Here is the code.


You can use ServiceStack.Redis high-level IRedisTypedClient Typed API for managing rich POCO Types.

First get a typed Redis client for Customers with:

var redisCustomers = redis.As<Customer>();

Which will resolve a high-level typed API for managing Customer POCO's that then lets you persist a single Customer with:

redisCustomers.SetEntry("Customer1", CustomerObject);

Or a list of Customers with:

redisCustomers.Lists["Customers"].AddRange(ListOfCustomer);


StackExchange.Redis has already predefined functions to deal with list and set of values.

Get IDatabase object :

string cacheConnection = Utils.Sections.Storage.RedisCache.ConnectionString;

IDatabase cache = ConnectionMultiplexer.Connect(cacheConnection).GetDatabase();

methods of list :

cache.ListLeftPushAsync(key, values) -> push one of list of elements

cache.ListRangeAsync(key, startIndex, endIndex) -> get list of values

cache.KeyExpire(key, timspan)

please package StackExchange.Redis for more methods. You don't need to include any extra nuget package.