Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert object to HashEntry in StackExchange.Redis

I want to make HashSet in redis use StackExchange.Redis,But in db.HashSet() I should pass HashEntry type , How I can convert object to HashEntry , I Know reflection ,Is there fast code for convert object?

like image 405
Amir Movahedi Avatar asked Aug 12 '14 12:08

Amir Movahedi


3 Answers

I know it's been more than 6 years but when i search that still the information is too much distributed on internet. So i decide to write here if someone need it.

There are 2 method down below. ToHashEntries for write object to redis and ConvertFromRedis for read object from redis.

Note: I used Newtonsoft.Json library as json converter.

    public static HashEntry[] ToHashEntries(object obj)
    {
        PropertyInfo[] properties = obj.GetType().GetProperties();
        return properties
            .Where(x => x.GetValue(obj) != null) // <-- PREVENT NullReferenceException
            .Select
            (
                  property =>
                  {
                      object propertyValue = property.GetValue(obj);
                      string hashValue;

                      // This will detect if given property value is 
                      // enumerable, which is a good reason to serialize it
                      // as JSON!
                      if (propertyValue is IEnumerable<object>)
                      {
                          // So you use JSON.NET to serialize the property
                          // value as JSON
                          hashValue = JsonConvert.SerializeObject(propertyValue);
                      }
                      else
                      {
                          hashValue = propertyValue.ToString();
                      }

                      return new HashEntry(property.Name, hashValue);
                  }
            )
            .ToArray();
    }

    public static T ConvertFromRedis<T>(HashEntry[] hashEntries)
    {
        PropertyInfo[] properties = typeof(T).GetProperties();
        var obj = Activator.CreateInstance(typeof(T));
        foreach (var property in properties)
        {
            HashEntry entry = hashEntries.FirstOrDefault(g => g.Name.ToString().Equals(property.Name));
            if (entry.Equals(new HashEntry())) continue;
            property.SetValue(obj, Convert.ChangeType(entry.Value.ToString(), property.PropertyType));
        }
        return (T)obj;
    }

Usage:

public class RedisContext
{
    private static RedisContext _redisContext;
    private static IDatabase _redis;

    private RedisContext()
    {
        _redis = ConnectionMultiplexer.Connect(Utils.REDIS_HOST).GetDatabase();
    }

    public static RedisContext GetInstance()
    {
        if (_redisContext == null)
            _redisContext = new RedisContext();
        return _redisContext;
    }

    public void set<T>(string key, T obj)
    {
        if (typeof(T) == typeof(string))
            _redis.StringSet(key, obj.ToString());
        else
            _redis.HashSet(key, RedisConverter.ToHashEntries(obj));
    }

    public T get<T>(string key)
    {
        if (typeof(T) == typeof(string))
            return (T)Convert.ChangeType(_redis.StringGet(key), typeof(T));
        else
            return RedisConverter.ConvertFromRedis<T>(_redis.HashGetAll(key));
    }
}
like image 55
Kadir Kalkan Avatar answered Nov 10 '22 16:11

Kadir Kalkan


The library does not currently include any layer for mapping a hash to/from an object and related properties. If you want that, you would have to do that separately, perhaps using something like reflection, but perhaps using a helper tool like FastMember or HyperDescriptor.

like image 30
Marc Gravell Avatar answered Nov 10 '22 16:11

Marc Gravell


Expanding on Kadir Kalkan's answer, here is the solution if the HashEntry contains an Enum.

Replace line property.SetValue(obj, Convert.ChangeType(entry.Value.ToString(), property.PropertyType)); with:

            object? propValue;
            if (property.PropertyType.IsEnum)
            {
                propValue = Enum.Parse(property.PropertyType, entry.Value.ToString(), true);
            }
            else
            {
                propValue = Convert.ChangeType(entry.Value.ToString(), property.PropertyType);
            }

            property.SetValue(obj, propValue);
like image 3
Quad Coders Avatar answered Nov 10 '22 15:11

Quad Coders