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.