当 Redis 中存储的数据越来越多,直接使用 StackExchange.Redis 手写键名、手动序列化对象会让代码变得冗长且易错。Redis OM .NET 提供了一种接近 ORM 的对象映射方式,允许开发者用声明式特性把 C# 类映射到 Redis JSON 文档或 Hash 结构,同时支持 LINQ 查询和聚合操作。下面围绕安装、模型定义、CRUD 以及查询展开。

一、安装与初始化 Redis OM .NET
Redis OM .NET 的 NuGet 包名称为 Redis.OM,依赖 StackExchange.Redis。在 Visual Studio 的包管理器控制台执行 Install-Package Redis.OM 即可完成安装。安装完成后,需要先创建 ConnectionMultiplexer 来连接 Redis 实例,再将其传递给 RedisConnectionProvider,这个 Provider 是后续所有对象映射操作的入口。
using Redis.OM;
using StackExchange.Redis;
var connection = ConnectionMultiplexer.Connect("localhost");
var provider = new RedisConnectionProvider(connection);
上面代码中 localhost 表示本机 Redis 服务,如果 Redis 部署在远程服务器,需要替换为对应的 IP 或域名,连接字符串与 StackExchange.Redis 完全兼容。拿到 provider 后,可以调用 RedisCollection<T> 方法获得强类型集合,再执行 CreateIndexAsync 创建索引。这一步相当于在 Redis 内部建立 RediSearch 索引,没有索引时 LINQ 查询会直接抛错或退化为全表扫描。
二、模型定义与索引策略
对象映射的核心在于模型类上的特性标记。一个类只有加上 Document 特性才会被 Redis OM .NET 识别为可映射文档,StorageType 枚举支持 Json 和 Hash 两种存储形式。默认情况下使用 Json,因为它能保留嵌套对象结构,也更适合后续搜索和聚合。主键属性需要用 RedisId 标记,Redis OM .NET 会自动生成 ULID 格式的字符串主键,也可以手动指定 Id 值。
using Redis.OM.Modeling;
[Document(StorageType = StorageType.Json)]
public class Person
{
[RedisId]
public string Id { get; set; }
[Searchable]
public string Name { get; set; }
[Indexed]
public int Age { get; set; }
[Indexed]
public string Email { get; set; }
public Address Address { get; set; }
}
public class Address
{
public string City { get; set; }
public string Street { get; set; }
}
Searchable 和 Indexed 的区别需要弄清楚:Indexed 用于精确匹配和范围查询,比如年龄、邮箱等字段;Searchable 除了支持精确匹配外还能做全文搜索,适合名称、描述这类文本字段。对于嵌套对象 Address,不需要额外特性,因为 JSON 序列化会把它作为子文档存储,查询时可以通过点号路径访问内部属性。如果某些属性不希望被索引,可以不加任何标记,它们仍然会存储,但不会参与查询转译。
三、使用 RedisCollection 完成 CRUD
RedisCollection<T> 是 Redis OM .NET 提供的强类型集合,内部封装了键名生成、序列化和反序列化。插入一条记录只需要创建对象并调用 InsertAsync,Redis OM .NET 会根据类名和主键自动拼接键名,默认格式类似 Person:01J2...,这样再也不用手动拼 Redis 键。
var people = provider.RedisCollection<Person>();
var person = new Person
{
Name = "Alice",
Age = 30,
Email = "alice@ipipp.com",
Address = new Address { City = "Shanghai", Street = "Nanjing Road" }
};
await people.InsertAsync(person);
查询单条记录使用 FindByIdAsync,更新和删除也只需调用对应方法。值得注意的是,UpdateAsync 会整体覆盖原文档,如果只改了一个字段,需要先查出来再修改再更新,避免丢失未携带的属性。删除时同样基于主键定位,不需要关心实际存储结构。
var found = await people.FindByIdAsync(person.Id); found.Age = 31; await people.UpdateAsync(found); await people.DeleteAsync(found);
四、查询与聚合进阶
Redis OM .NET 支持将 LINQ 表达式转换为 RediSearch 查询语句。Where、OrderBy、Skip、Take 等操作可以直接在 RedisCollection 上使用,返回类型为 List<T> 或 IAsyncEnumerable。这意味着开发者可以用熟悉的 C# 语法完成条件过滤、排序和分页,而不用拼接复杂的查询字符串。
var adults = await people
.Where(p => p.Age >= 18)
.OrderBy(p => p.Name)
.ToListAsync();
var page = await people
.Where(p => p.Age > 20)
.Skip(10)
.Take(10)
.ToListAsync();
聚合场景下可以使用 provider.AggregationSet<T>() 构建聚合管道,比如按年龄分组统计人数。聚合比普通查询更依赖索引,如果某个字段没有加 Indexed 特性,聚合会失败。另外,查询返回值中的 DateTime、枚举等类型在序列化时会受到配置影响,建议在模型定义阶段统一使用字符串或数值存储,避免类型不匹配导致搜索异常。
总体来看,Redis OM .NET 大幅降低了 .NET 应用集成 Redis 的门槛,尤其是对于已经习惯 Entity Framework 等 ORM 的开发者,上手速度会很快。不过它仍然依赖 RediSearch 模块,使用前需要确认 Redis 版本和模块是否开启。
Redis OM .NETC#对象映射修改时间:2026-10-01 13:00:00