【问题标题】:How to add Generic List to Redis via StackExchange.Redis?如何通过 StackExchange.Redis 将通用列表添加到 Redis?
【发布时间】:2014-11-11 22:45:06
【问题描述】:

例如,如果我有一个名为 Customer 的模型

public class Customer
    {
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Address1 { get; set; }
        public string City { get; set; }
        public string State { get; set; }
    }

例子:

var customers = new List<Customer>();

如何添加客户列表?我该怎么做?

 using (var redis = ConnectionMultiplexer.Connect(this.redisServer))
            {
                var db = redis.GetDatabase();

                db.SetAdd(key, ?????);
}

我认为 SetAdd 是正确的方法,但我看不到如何获取我的通用客户列表(即列表为 RedisValue 的格式。

【问题讨论】:

    标签: c# redis stackexchange.redis


    【解决方案1】:

    可能会有所帮助。在开始研究 StackExchange.Redis 时,我也遇到了同样的问题。在我的项目中,我创建了 2 个扩展方法,它们帮助我序列化/反序列化 Redis 数据库的复杂类型。您可以将它们扩展到您的需要。

    方法:

        public static class RedisUtils
            {
    //Serialize in Redis format:
                public static HashEntry[] ToHashEntries(this object obj)
                {
                    PropertyInfo[] properties = obj.GetType().GetProperties();
                    return properties.Select(property => new HashEntry(property.Name, property.GetValue(obj).ToString())).ToArray();
                }
        //Deserialize from Redis format
                public static T ConvertFromRedis<T>(this 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;
                }
            }
    

    用法:

    var customer = new Customer
    {
    //Initialization
    };
    
    Db.HashSet("customer", customer.ToHashEntries());
    Customer result = Db.HashGetAll("customer").ConvertFromRedis<Customer>();
    
    Assert.AreEqual(customer.FirstName, result.FirstName);
    Assert.AreEqual(customer.LastName, result.LastName);
    Assert.AreEqual(customer.Address1, result.Address1);
    

    【讨论】:

    • 假设 OP 询问的 Customer 类有一个自定义对象,比如 Product。在这种情况下,您能解释一下如何进行吗?
    【解决方案2】:

    StackExchange.Redis 是一个原始客户端 - 它只使用 Redis 术语。它不会尝试成为任何类型的 ORM。但是,它会存储您想扔给它的任何stringbyte[]——这意味着您应该可以选择序列化程序。 JSON 将是一个合理的默认值(Jil 很棒),尽管我们倾向于自己使用协议缓冲区(通过 protobuf-net)。

    如果您打算使用列表语义,我强烈建议您从 List* 命令开始 - 集合与列表具有不同的语义 - 集合是无序的并且只存储唯一值;列表保留顺序并允许重复。

    【讨论】:

    • 明白。所以我可能会将我的通用客户列表序列化为 Json(通过 newtonsoft 或其他方式),然后我可以保存为字符串并来回序列化/反序列化?我会检查 List 命令。
    • @Shane 两个选项 - 如果您想使用 redis 的列表功能,请单独序列化每个对象并作为单独的列表行发送。如果您只想“存储我的列表,获取我的列表” - 那么:序列化 list 并使用 String* redis 函数。 redis“字符串”仅表示“单个值” - 它不需要是 string (如果有意义的话)
    • 或者,您可以将像 Customer 这样的对象存储为哈希值,然后对集合进行排序以将它们分组到“列表”中。这实际上很酷,因为您可以让同一个客户在不同的“列表”中(完全合理)并且只存储一次。并且很容易在“列表”之间移动。
    【解决方案3】:

    Andrey Gubal 的答案的改进,以处理可空属性或空值:

    public static class RedisUtils
    {
        //Serialize in Redis format:
        public static HashEntry[] ToHashEntries(this object obj)
        {
            PropertyInfo[] properties = obj.GetType().GetProperties();
            return properties
                .Where(x=> x.GetValue(obj)!=null) // <-- PREVENT NullReferenceException
                .Select(property => new HashEntry(property.Name, property.GetValue(obj)
                .ToString())).ToArray();
        }
    
        //Deserialize from Redis format
        public static T ConvertFromRedis<T>(this 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;
        }
    }
    

    【讨论】:

      【解决方案4】:

      这是一个选项

      public static class StackExchangeRedisExtensions
      {
      
          public static T Get<T>(string key)
          {
              var connect = AzureredisDb.Cache;
              var r = AzureredisDb.Cache.StringGet(key);
              return Deserialize<T>(r);
          }
      
          public static List<T> GetList<T>(string key)
          {                       
              return (List<T>)Get(key);
          }
      
          public static void SetList<T>(string key, List<T> list)
          {
              Set(key, list);
          }
      
          public static object Get(string key)
          {
              return Deserialize<object>(AzureredisDb.Cache.StringGet(key));
          }
      
          public static void Set(string key, object value)
          {
              AzureredisDb.Cache.StringSet(key, Serialize(value));
          }
      
          static byte[] Serialize(object o)
          {
              if (o == null)
              {
                  return null;
              }
      
              BinaryFormatter binaryFormatter = new BinaryFormatter();
              using (MemoryStream memoryStream = new MemoryStream())
              {
                  binaryFormatter.Serialize(memoryStream, o);
                  byte[] objectDataAsStream = memoryStream.ToArray();
                  return objectDataAsStream;
              }
          }
      
          static T Deserialize<T>(byte[] stream)
          {
              if (stream == null)
              {
                  return default(T);
              }
      
              BinaryFormatter binaryFormatter = new BinaryFormatter();
              using (MemoryStream memoryStream = new MemoryStream(stream))
              {
                  T result = (T)binaryFormatter.Deserialize(memoryStream);
                  return result;
              }
          }
      }
      

      AzureredisDb.Cache 是 СonnectionMultiplexer.Connect 和 GetDatabase();

      【讨论】:

      猜你喜欢
      • 2019-09-28
      • 2020-04-20
      • 2021-06-29
      • 2015-06-18
      • 2023-03-12
      • 2016-10-02
      • 1970-01-01
      • 2020-01-06
      • 2015-12-11
      相关资源
      最近更新 更多