Как добавить общий список в Redis через StackExchange.Redis?

Например, если у меня есть модель с именем 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.


person Shane    schedule 17.09.2014    source источник


Ответы (4)


StackExchange.Redis — это сырой клиент, он говорит только в терминах Redis. Он не пытается быть ORM любого рода. Однако он будет хранить любые string или byte[], которые вы захотите использовать, а это значит, что у вас должен быть выбор сериализаторов. JSON был бы разумным значением по умолчанию (Jil великолепен), хотя мы сами склонны использовать протокольные буферы (через protobuf-net).

Если вы собираетесь использовать семантику списка, я настоятельно рекомендую начать с команд List* — наборы имеют другую семантику, чем списки — наборы неупорядочены и хранят только уникальные значения; списки сохраняют порядок и допускают дублирование.

person Marc Gravell    schedule 17.09.2014
comment
Понял. Итак, я бы, возможно, сериализовал свой общий список клиентов в Json (через newtonsoft или что-то еще), тогда я мог бы сохранить как строку и просто сериализовать/десериализовать туда и обратно? Я проверю команды списка. - person Shane; 17.09.2014
comment
@Shane два варианта: если вы хотите использовать функции списка Redis, сериализуйте каждый объект отдельно и отправьте в виде отдельных строк списка. Если вы просто хотите сохранить мой список, получить мой список - затем: сериализовать список и использовать функции String* Redis. Строка Redis просто означает одно значение — это не обязательно должна быть строка (если это имеет смысл) - person Marc Gravell; 17.09.2014
comment
ИЛИ вы можете хранить такие объекты, как Customer, в виде хэшей, а затем иметь отсортированные наборы для группировки их в списки. Это на самом деле круто, потому что вы можете иметь одного и того же клиента в разных списках (вполне разумно) и хранить их только один раз. И легко перемещаться между списками. - person Philip P.; 19.09.2014

Может быть, это помогает. Я также столкнулся с тем же вопросом в начале своего погружения в 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);
person Andrey Gubal    schedule 09.11.2014
comment
Предположим, что класс Customer, запрошенный OP, имеет настраиваемый объект, например Product. В таком случае не могли бы вы объяснить, как действовать дальше? - person Karan Desai; 12.04.2017

Улучшение ответа Andrey Gubal для обработки свойств, допускающих значение NULL, или нулевых значений:

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;
    }
}
person von v.    schedule 17.08.2015

это вариант

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();

person Andrey Fedorov    schedule 22.03.2015
comment
Как правило, избегайте ответов, содержащих только код. Попробуйте добавить description, который поможет объяснить ваш код. Спасибо - person MickyD; 23.03.2015
comment
хранение двоичных данных - действительно плохой подход IMO - person knocte; 14.10.2018