C#中如何将List<T>存入Redis并支持分页与多列排序?
在C#中实现Redis存储List并支持多列分页排序的方案
答案是可以实现,且无需为不同排序列重复插入数据,以下是几种可行方案:
方案一:RedisJSON + RedisSearch(推荐)
- 把
List<T>中的每个实体序列化为JSON,用Redis原生JSON类型(Redis 6.2+支持)存储,每个实体分配唯一ID作为Key,例如entity:{实体ID}。 - 利用RedisSearch创建全局索引,指定所有需要排序的字段(如
Name、CreateTime、Score等),索引只需创建一次。 - 查询时直接通过RedisSearch命令指定排序字段、分页参数(偏移量+条数),即可直接获取分页排序后的结果,无需冗余存储。
- C#代码示例(基于NRedisStack库):
// 序列化并存储单个实体 var entityJson = JsonSerializer.Serialize(myEntity); db.Json.Set($"entity:{myEntity.Id}", "$", entityJson); // 创建索引(仅需执行一次) db.CreateIndex("entities_index", new FTCreateIndexOptions().On(IndexDataType.Json).Prefix("entity:"), new Schema() .AddSortableField("$.Name") .AddSortableField("$.CreateTime") .AddSortableField("$.Score") ); // 按CreateTime降序分页查询(第2页,每页10条) var searchResult = db.Search("entities_index", new Query("*").SortBy("$.CreateTime", Order.Descending).Limit(10, 10) ); // 反序列化为List<T> var sortedEntities = searchResult.Documents .Select(doc => JsonSerializer.Deserialize<T>(doc.ToString())) .ToList(); - 优势:一次存储支持多字段排序、分页、复杂过滤,性能优异,无冗余数据。
方案二:Hash存储实体 + 复合键SortedSet
如果无法依赖RedisSearch模块,可通过构造复合排序键实现多规则排序:
- 将每个实体存入Redis Hash,Key为
entity:{实体ID},字段对应实体的各个属性。 - 创建一个SortedSet,成员为实体ID,排序键用复合字符串拼接(需保证字典序与实际排序逻辑一致),例如按
CreateTime降序+Score升序,可构造键为{反转时间字符串}_{补零后的Score}。 - 查询时通过SortedSet的范围命令分页获取实体ID,再批量从Hash中取出实体。
- C#代码示例:
// 存储实体到Hash db.HashSet($"entity:{entity.Id}", new HashEntry[] { new HashEntry("Name", entity.Name), new HashEntry("CreateTime", entity.CreateTime.ToString("o")), new HashEntry("Score", entity.Score.ToString("D8")) // 补前导零保证长度一致 }); // 构造复合排序键(时间反转实现降序) var reverseTime = new string(entity.CreateTime.ToString("yyyyMMddHHmmss").Reverse().ToArray()); var sortKey = $"{reverseTime}_{entity.Score.ToString("D8")}"; // 将复合键作为SortedSet的成员,分数设为0,利用字典序排序 db.SortedSetAdd("entities_sort", sortKey, 0); // 分页获取排序后的实体ID var sortedKeys = db.SortedSetRangeByLex("entities_sort", "-", "+", order: Order.Ascending, skip: 10, take: 10); var entityIds = sortedKeys.Select(k => k.Split('_')[1]); // 解析出实体ID // 批量获取实体并映射为T类型 var entities = entityIds.Select(id => MapHashToEntity<T>(db.HashGetAll($"entity:{id}"))).ToList(); - 注意:复合键的构造需严格保证字典序与业务排序逻辑匹配,适合排序规则相对固定的场景。
方案三:应用层分页排序(仅适合小数据集)
- 将整个
List<T>序列化为JSON字符串存入Redis String类型。 - 取出时反序列化为
List<T>,通过C# Linq完成分页排序:var listJson = db.StringGet("full_entity_list"); var entityList = JsonSerializer.Deserialize<List<T>>(listJson); var sortedPage = entityList.OrderBy(x => x.Name).Skip(10).Take(10).ToList(); - 劣势:数据量大时序列化/反序列化开销极高,占用内存大,性能差。
内容的提问来源于stack exchange,提问作者ivan
相关产品推荐
相关产品推荐

