dot 速度的未来即将在您所在的城市举办的活动中亮相。

加入我们在 Redis 发布会

Redis OM .NET 更新

嵌入式文档、索引数组以及 Redis OM .NET 的其他令人惊叹的补充!

2021 年 11 月,我们发布了 Redis OM .NET(用于 Redis 的对象映射库)的 v0.1.0 版本。当然,与任何早期发布的软件一样,还有更多工作要做。从那时起,我们解决了一些库的怪癖。我们还为 .NET 添加了一些激动人心的新功能,以便开发人员能够快速提高生产力。

在查看新增功能之前,如果您需要 Redis OM 的总体概述,可以查看 公告帖子 或观看下面的视频。

https://www.youtube.com/embed/DFNKmbGKa5w

现在,让我们来看看为 Redis OM .NET 添加的新功能!

嵌入式对象索引和查询

Redis OM .NET 现在允许您索引模型中嵌入对象中的字段。例如,假设您有一个 Customer 模型,其中包含一个嵌入式 Address 模型。

[Document(StorageType = StorageType.Json)]
public class Customer
{
   [Indexed] public string FirstName { get; set; }
   [Indexed] public string LastName { get; set; }
   public string Email { get; set; }
   public Address Address {get; set;}
}

public class Address
{
    public string StreetName { get; set; }
    public string ZipCode { get; set; }
    public string City { get; set; }
    public string State { get; set; }
    public GeoLoc Location { get; set; }
    public int HouseNumber { get; set; }
}

以前,您无法索引 Customer 中的嵌入式 Address。现在,Redis OM .NET 提供了两种方法来执行此操作。

直接 JSON 路径

假设您想在其他模型之间共享嵌入式模型,并且不想过度索引嵌入式模型中的字段。

您可以保留嵌入式模型,并使用相对于模型根部的 JSON 路径从您的模型对其进行索引。要索引 Customer 的 Address 中的 City 和 State,请执行以下操作

[Document(StorageType = StorageType.Json)]
public class Customer
{
   [Indexed] public string FirstName { get; set; }
   [Indexed] public string LastName { get; set; }
   public string Email { get; set; }
   [Indexed(JsonPath = "$.City")]
   [Indexed(JsonPath = "$.State")]
   public Address Address {get; set;}
}

级联到嵌入式文档

完成此操作的另一种方法是声明要在 Address 类中索引的内容,并使用 IndexedAttribute 的“CascadeDepth”属性级联到它。因此,使用以下 Address 模型

[Document(StorageType = StorageType.Json)]
public class Address
{
    public string StreetName { get; set; }
    public string ZipCode { get; set; }
    [Indexed] public string City { get; set; }
    [Indexed] public string State { get; set; }
    [Indexed] public GeoLoc Location { get; set; }
    [Indexed] public int HouseNumber { get; set; }
}

您可以像这样从您的 Customer 模型中进行索引

[Document(StorageType = StorageType.Json)]
public class Customer
{
   [Indexed] public string FirstName { get; set; }
   [Indexed] public string LastName { get; set; }
   public string Email { get; set; }
   [Indexed(CascadeDepth=1)]
   public Address Address {get; set;}
}

CascadeDepth 指的是您想要索引的对象图的深度。设置级联深度将导致 Redis OM 遵循所有 IndexedAttributeSearchableAttribute 用于索引模型对象图中的字段。

遵循其中一种模式后,当您创建索引时,嵌入式文档将按预期进行索引,然后当您运行如下所示的 LINQ 查询时

customers.Where(c=>c.Address.ZipCode == "10001");

…Redis OM 知道如何根据提供的模型正确构建查询。

可查询数组

自 v0.1.0 以来,我们在 Redis OM 中添加的另一个很棒的功能是能够索引和查询 JSON 对象中的字符串数组。使用 IndexedAttribute 来修饰数组。

[Document(StorageType = StorageType.Json, Prefixes = new []{"Person"})]
public class Person
{

    [RedisIdField] [Indexed]public string? Id { get; set; }
    [Indexed] public string[] Skills { get; set; } = Array.Empty<string>();    
    [Indexed] public string? FirstName { get; set; }
    [Indexed] public string? LastName { get; set; }
}

完成此操作后,您可以使用数组的 Contains 方法查询这些数组

people.Where(x => x.Skills.Contains(skill));

索引枚举、ULID、GUID 和布尔值

Redis OM 以前仅支持数字、字符串和 GeoLoc 的索引。自 0.2.0 版本起,您还可以索引枚举、ULID、GUID 和布尔值。为此,请使用 IndexedAttribute 来修饰模型中的这些字段。

聚合未标记为可聚合的字段

对于聚合用户的痛点之一是,并非所有字段都可以或一定标记为可聚合的。因此,这些字段以前在 Redis OM 中无法用于聚合。使用 Redis OM 中 AggregationSet 中的新 Load 和 LoadAll 方法,现在可以加载未标记为可聚合的字段。

让我们以我们之前使用的 Customer 模型为例,并添加一个 age 字段来演示其工作原理。

public class Customer
{
    [Indexed] public string FirstName { get; set; }
    [Indexed] public string LastName { get; set; }
    [Indexed] public int Age { get; set; }
    public string Email { get; set; }
    [Indexed(JsonPath = "$.City")]
    [Indexed(JsonPath = "$.State")]
    public Address Address {get; set;}
}

Age 已被索引,但未标记为可聚合的。以前,我们无法在聚合管道中使用 Age。如果我们运行类似以下代码,我们将收到错误,因为 Age 未在管道中加载。

var aggregations = provider.AggregationSet<Customer>();
await aggregations.Apply(c=>c.RecordShell.Age + 5, "Age_plus_five")
    .ToArrayAsync();

现在,在 Redis OM .NET 中,您可以调用 AggregationSet 上的 Load,加载单个字段或多个字段(通过初始化匿名对象)。

await aggregations.Load(x=>x.RecordShell.Age)
    .Apply(c=>c.RecordShell.Age + 5, "Age_plus_five")
    .ToArrayAsync();

仅加载 Age,或者

await aggregations.LoadAll
    .Apply(c=>c.RecordShell.Age + 5, "Age_plus_five")
    .Apply(c=>string.Format("My Name is {0}",c.RecordShell.FirstName), "myNameIs")
    .ToArrayAsync();

加载模型中的多个字段,请注意匿名类型。

新的水合 API

聚合的另一个怪癖是它们不返回格式良好的对象。造成这种情况的原因是,聚合会返回其管道的结果,这通常正是其完成所有请求的操作所需的结果及其操作的结果。现在这个问题已经解决了。

使用新的水合 API,您可以将这些片段整理成更易用的格式,使您能够从 RedisAggreagtionResult 中完全或部分水合您的模型。

让我们回顾一下 Load 部分中的示例。如果我们想将整个 customer 模型以及 apply 函数的结果带回来,该怎么办?我们可以通过调用 LoadAll 而不是 Load 来实现。然后,当枚举每个 RedisAggregationResult 时,我们调用其上的 Hydrate。Hydrate 尝试将 AggregationResult 中的任何内容绑定到您的模型。因此,可能存在 AggregationResult 中不存在的空字段。

var collection = new RedisAggregationSet<Person>(_connection);
await foreach (var result in aggregations.LoadAll
    .Apply(c=>c.RecordShell.Age + 5, "Age_plus_five")
    .Apply(c=>string.Format("My Name is {0}",c.RecordShell.FirstName), "myNameIs"))
{
    var person = result.Hydrate(); //now a fully hydrated Person object!
}

简化的对象更新

在 Redis OM 的先前版本中,如果您想更新一项,则需要枚举它、更新它,然后保存整个 RedisCollection。这可能很繁琐。我们添加了一个新的 API,使您能够轻松更新存储在 Redis 中的对象。

await collection.UpdateAsync(object);

更简单的删除

同样,我们也简化了删除您插入 Redis 中的对象的操作。要删除对象,请执行以下操作

await customers.DeleteAsync(object);

自建 ConnectionMultiplexer

一个请求的功能是传递 ConnectionMultiplexer 来初始化 RedisConnectionProvider。此构造函数允许您使用已注入到 Redis OM 的其他服务中的任何多路复用器。

可配置的块大小

Redis OM 现在支持可配置的块大小,以便在后台进行自动分页。以前,固定的块大小可能会对巨大的查询结果产生性能影响。较小且不可配置的块大小与大型结果集相结合会导致 Redis OM 必须进行许多往返操作才能实现整个结果集。现在,您可以将所需的块大小传递给 Redis OM。

var customers = provider.RedisCollection<Customer>(10000);

请注意,这取决于 RediSearch 中的 MAXSEARCHRESULT 配置参数。

总结

在过去几个月里,我们一直在做很多事情,为 Redis OM .NET 添加了许多激动人心的新功能,以及任何软件都会遇到的不可避免的错误修复。您可以通过关注 GitHub 存储库 来关注新功能。如果您想在库中看到的功能,请在 GitHub 上创建一个问题。

资源

  • 一个演示如何将 Redis OM .NET 集成到您的 ASP.NET Core 应用程序中的骨架应用程序可在 GitHub 上获取。
  • Redis 开发者网站上的一个教程详细介绍了如何使用 Redis OM .NET。
  • Redis OM .NET 的参考文档可在存储库的 github-pages 网站 上获取。
  • 如果您对库有任何问题,请在 GitHub 上创建一个问题,或在 Redis Discord 服务器 上与我们联系。