This capability is a part of Redis Stack - Redis 内存数据库 Redis OM .NET

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

Redis OM .NET 是一个专门用于处理 Redis Stack 中文档的库。在本教程中,我们将构建一个简单的 ASP.NET Core Web-API 应用程序,用于对简单的人员和地址模型执行 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 中创建索引。管理此操作最正确的方法是将索引创建分离到托管服务中,该服务将在应用程序启动时运行。创建 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.csPeopleController 类的框架将是

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 的第一个路由是用于创建人员的 POST 请求,使用 RedisCollection,它和调用 InsertAsync 一样简单,传入人员对象

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

更新人员

可以使用 Redis OM 更新 Redis Stack 中的文档,首先将人员对象具体化,进行所需的更改,然后在集合上调用 Save。该集合负责跟踪在其中具体化的实体所做的更新;因此,它将跟踪和应用您在其中进行的任何更新。例如,添加以下路由以根据人员的 Id 更新其年龄

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

删除人员

可以使用 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 中找到。

为本页评分