RedisOM for .NET

了解如何使用 Redis Stack 和 .NET 进行构建

Redis OM .NET 是一个专门用于处理 Redis Stack 中文档的库。在本教程中,我们将构建一个简单的 ASP.NET Core Web-API 应用程序,用于对一个简单的 Person 和 Address 模型执行 CRUD 操作,我们将使用 Redis OM .NET 完成所有这些任务。

前提条件

  • .NET 6 SDK
  • 用于编写 .NET 的任何 IDE(Visual Studio、Rider、Visual Studio Code)。
  • RediSearch 必须作为 Redis Stack 配置的一部分进行安装。
  • 可选:Docker Desktop 用于在 Docker 中运行 redis-stack 以进行本地测试。

跳至代码

如果你想跳过本教程直接查看代码,所有源代码都可在 GitHub 上找到

运行 Redis Stack

运行 Redis Stack 的方法有很多种。一种方法是使用 Docker 镜像

docker run -d -p 6379:6379 -p 8001:8001 redis/redis-stack

创建项目

要创建项目,只需运行

dotnet new webapi -n Redis.OM.Skeleton --no-https --kestrelHttpPort 5000

然后在你选择的 IDE 中打开 Redis.OM.Skeleton.csproj 文件。

配置应用程序

在你的 appsettings.json 文件中添加一个 REDIS_CONNECTION_STRING 字段来配置应用程序。将连接字符串设置为你的 Redis 实例的 URI。如果使用前面提到的 Docker 命令,你的连接字符串将是 redis://localhost:6379

连接字符串规范

Redis URI 的规范位于此处。对于不包含 username 的连接字符串,你可以使用 :password@host:portdefault:password@host:port

创建模型

确保将 Redis.OM 包添加到你的项目中。这个包可以轻松创建模型并查询你的 Redis 领域对象。

dotnet add package Redis.OM     

现在是时候创建应用程序将用于存储/检索人员的 Person/Address 模型了。创建一个名为 Model 的新目录,并将 Address.csPerson.cs 文件添加到其中。在 Address.cs 中,添加以下内容

using Redis.OM.Modeling;

namespace Redis.OM.Skeleton.Model;

public class Address
{
    [Indexed]
    public int? StreetNumber { get; set; }
    
    [Indexed]
    public string? Unit { get; set; }
    
    [Searchable]
    public string? StreetName { get; set; }
    
    [Indexed]
    public string? City { get; set; }
    
    [Indexed]
    public string? State { get; set; }
    
    [Indexed]
    public string? PostalCode { get; set; }
    
    [Indexed]
    public string? Country { get; set; }
    
    [Indexed]
    public GeoLoc Location { get; set; }
}

在这里,你会注意到除了标记为 SearchableStreetName 之外,所有字段都使用 Indexed 属性进行修饰。这些属性(SearchableIndexed)告诉 Redis OM 你希望在查询 Redis Stack 中的文档时能够在查询中使用这些字段。Address 本身不会是一个文档,因此顶级类没有用任何东西修饰;相反,Address 模型将嵌入到我们的 Person 模型中。

为此,请将以下内容添加到 Person.cs

using Redis.OM.Modeling;

namespace Redis.OM.Skeleton.Model;

[Document(StorageType = StorageType.Json, Prefixes = new []{"Person"})]
public class Person
{    
    [RedisIdField] [Indexed]public string? Id { get; set; }
    
    [Indexed] public string? FirstName { get; set; }

    [Indexed] public string? LastName { get; set; }
    
    [Indexed] public int Age { get; set; }
    
    [Searchable] public string? PersonalStatement { get; set; }
    
    [Indexed] public string[] Skills { get; set; } = Array.Empty<string>();    
    
    [Indexed(CascadeDepth = 1)] public Address? Address { get; set; }
    
}

这里有几点需要注意

  1. [Document(StorageType = StorageType.Json, Prefixes = new []{"Person"})] 指示 Redis OM 将用于在 Redis 中存储文档的数据类型是 JSON,并且 Person 类的键前缀将是 Person

  2. [Indexed(CascadeDepth = 1)] Address? Address { get; set; } 是使用 Redis OM 索引嵌入对象两种方法之一。这种方法指示索引级联到对象图中的对象,CascadeDepth 为 1 意味着它将仅遍历一层,就像从头构建索引一样索引对象。另一种方法是使用你想要搜索的各个索引字段的 JsonPath 属性。这种更精确的方法限制了索引的大小。

  3. Id 属性被标记为 RedisIdField。这表示该字段将用于在 Redis 中存储文档时生成文档的键名。

创建索引

构建模型后,下一步是在 Redis 中创建索引。管理此过程最正确的方法是将索引创建分离到一个 Hosted Service 中,该服务将在应用程序启动时运行。创建一个名为 HostedServices 的目录,并将 IndexCreationService.cs 添加到其中。在该文件中,添加以下内容,这将在启动时创建索引。

using Redis.OM.Skeleton.Model;

namespace Redis.OM.Skeleton.HostedServices;

public class IndexCreationService : IHostedService
{
    private readonly RedisConnectionProvider _provider;
    public IndexCreationService(RedisConnectionProvider provider)
    {
        _provider = provider;
    }
    
    public async Task StartAsync(CancellationToken cancellationToken)
    {
        await _provider.Connection.CreateIndexAsync(typeof(Person));
    }

    public Task StopAsync(CancellationToken cancellationToken)
    {
        return Task.CompletedTask;
    }
}

接下来,将以下内容添加到 Program.cs 中以在启动时注册服务

builder.Services.AddHostedService<IndexCreationService>();

注入 RedisConnectionProvider

Redis OM 使用 RedisConnectionProvider 类处理与 Redis 的连接,并提供可用于与 Redis 交互的类。要使用它,只需将 RedisConnectionProvider 实例注入到你的应用程序中。在你的 Program.cs 文件中,添加

builder.Services.AddSingleton(new RedisConnectionProvider(builder.Configuration["REDIS_CONNECTION_STRING"]));

这将从配置中提取连接字符串并初始化提供程序。现在,该提供程序将在你的控制器/服务中可用。

创建 PeopleController

最后一块拼图是为我们的 People API 编写实际的 API 控制器。在 controllers 目录中,添加 PeopleController.cs 文件,PeopleController 类的骨架将是

using Microsoft.AspNetCore.Mvc;
using Redis.OM.Searching;
using Redis.OM.Skeleton.Model;

namespace Redis.OM.Skeleton.Controllers;

[ApiController]
[Route("[controller]")]
public class PeopleController : ControllerBase
{

}

注入 RedisConnectionProvider

为了与 Redis 交互,注入 RedisConnectionProvider。在此依赖注入过程中,提取一个 RedisCollection<Person> 实例,它将提供一个流畅的接口用于查询 Redis 中的文档。

private readonly RedisCollection<Person> _people;
private readonly RedisConnectionProvider _provider;
public PeopleController(RedisConnectionProvider provider)
{
    _provider = provider;
    _people = (RedisCollection<Person>)provider.RedisCollection<Person>();
}

添加创建 Person 的路由

要添加到 API 的第一个路由是用于创建 Person 的 POST 请求,使用 RedisCollection,只需调用 InsertAsync 并传入 Person 对象即可。

[HttpPost]
public async Task<Person> AddPerson([FromBody] Person person)
{
    await _people.InsertAsync(person);
    return person;
}

添加按年龄过滤的路由

要添加到 API 的第一个过滤路由将允许用户按最小和最大年龄进行过滤。使用 RedisCollection 可用的 LINQ 接口,这是一个简单的操作

[HttpGet("filterAge")]
public IList<Person> FilterByAge([FromQuery] int minAge, [FromQuery] int maxAge)
{        
    return _people.Where(x => x.Age >= minAge && x.Age <= maxAge).ToList();
}

按地理位置过滤

Redis OM 有一个 GeoLoc 数据结构,它的一个实例由 Address 模型索引,使用 RedisCollection,可以通过 GeoFilter 方法和你想过滤的字段来查找特定位置半径内的所有对象。

[HttpGet("filterGeo")]
public IList<Person> FilterByGeo([FromQuery] double lon, [FromQuery] double lat, [FromQuery] double radius, [FromQuery] string unit)
{
    return _people.GeoFilter(x => x.Address!.Location, lon, lat, radius, Enum.Parse<GeoLocDistanceUnit>(unit)).ToList();
}

按精确字符串过滤

当模型中的字符串属性标记为 Indexed 时,例如 FirstNameLastName,Redis OM 可以对其执行精确文本匹配。例如,以下两个路由按 PostalCode 和名称进行过滤,演示了精确字符串匹配。

[HttpGet("filterName")]
public IList<Person> FilterByName([FromQuery] string firstName, [FromQuery] string lastName)
{
    return _people.Where(x => x.FirstName == firstName && x.LastName == lastName).ToList();
}

[HttpGet("postalCode")]
public IList<Person> FilterByPostalCode([FromQuery] string postalCode)
{
    return _people.Where(x => x.Address!.PostalCode == postalCode).ToList();
}

当模型中的属性标记为 Searchable 时,如 StreetAddressPersonalStatement,你可以执行全文搜索,请参见 PersonalStatementStreetAddress 的过滤器。

[HttpGet("fullText")]
public IList<Person> FilterByPersonalStatement([FromQuery] string text){
    return _people.Where(x => x.PersonalStatement == text).ToList();
}

[HttpGet("streetName")]
public IList<Person> FilterByStreetName([FromQuery] string streetName)
{
    return _people.Where(x => x.Address!.StreetName == streetName).ToList();
}

按数组成员过滤

当字符串数组或列表标记为 Indexed 时,Redis OM 可以使用数组或列表的 Contains 方法过滤所有包含给定字符串的记录。例如,我们的 Person 模型有一个技能列表,你可以通过添加以下路由进行查询。

[HttpGet("skill")]
public IList<Person> FilterBySkill([FromQuery] string skill)
{
    return _people.Where(x => x.Skills.Contains(skill)).ToList();
}

更新 Person

使用 Redis OM 更新 Redis Stack 中的文档可以通过先实例化 Person 对象,进行所需的更改,然后调用集合上的 Save 方法来完成。集合负责跟踪其中实例化的实体所做的更新;因此,它将跟踪并应用你在其中进行的任何更新。例如,添加以下路由以根据给定 ID 更新 Person 的年龄。

[HttpPatch("updateAge/{id}")]
public IActionResult UpdateAge([FromRoute] string id, [FromBody] int newAge)
{
    foreach (var person in _people.Where(x => x.Id == id))
    {
        person.Age = newAge;
    }
    _people.Save();
    return Accepted();
}

删除 Person

可以使用 Unlink 从 Redis 中删除文档。只需调用 Unlink 并传入键名即可。给定 ID,我们可以使用前缀和 ID 重构键名。

[HttpDelete("{id}")]
public IActionResult DeletePerson([FromRoute] string id)
{
    _provider.Connection.Unlink($"Person:{id}");
    return NoContent();
}

运行应用程序

现在剩下的就是运行应用程序并进行测试了。你可以通过运行 dotnet run 来实现,应用程序现在暴露在 5000 端口,并且应该有一个 Swagger UI,你可以在 http://localhost:5000/swagger 使用它来测试 API。在 GitHub 仓库中,有一些脚本和数据文件,可以使用 API 将一些人员插入到 Redis 中。

使用 Redis Insight 查看数据

你可以安装 Redis Insight GUI,或者使用运行在 http://localhost:8001/ 上的 Redis Insight GUI。

你可以按照以下步骤查看数据

  1. 接受 EULA

Accept EULA

  1. 点击添加 Redis 数据库按钮

Add Redis Database Button

  1. 输入你的 Redis 服务器的主机名和端口名。如果你正在使用 Docker 镜像,它们分别是 localhost6379,并为你的数据库指定一个别名。

Configure Redis Insight Database

  1. 点击 添加 Redis 数据库

资源

本教程的源代码可在 GitHub 上找到。

评价本页面
返回顶部 ↑