Redis OM .NET Redis Object Mapping Framework

Redis OM

Redis OM is an object mapping framework officially launched by Redis, namely: Object Mapping. Let developers operate Redis data more easily and conveniently. The data stored in Redis is abstracted into object mapping, which supports object-based Redis data persistence and streaming query operations.

Currently only 4 development languages ​​are supported:

  • Redis OM for Spring
  • Redis OM for .NET
  • Redis OM for Node.js
  • Redis OM for Python

Redis ABOUT .NET

Redis OM .NET is the Redis OM for the .Net platform and relies on the StackExchange.Redis implementation. With the help of Redis OM .NET, it is possible to operate Redis data in the way of object operation, and get rid of the operation mode of key/value. Queries support most of .Neter's favorite LINQ.

quick start

Install the corresponding package

dotnet add package Redis.OM

Redis environment preparation

Install the Redis environment directly using Docker.

docker run -p 6379:6379 redislabs/redismod:preview

The standard official image cannot support Redis OM, and requires Redis Modules support. The Redis OM core creates indexes and queries data depending on RediSearchthe implementation of this Module. Dependent Modules are: RediSearch, RedisJSON. The dependency of RedisJSON is not necessary, but it will lack corresponding functions, such as: model nesting, complex query (only support key query)

Coding

Add abstract object definition

[Document]
public class Customer
{
    [RedisIdField]
    public string Id { get; set; }
    [Indexed(Sortable = true, Aggregatable = true)]
    public string FirstName { get; set; }
    [Indexed(Sortable = true, Aggregatable = true)]
    public string LastName { get; set; }
    [Indexed]
    public string Email { get; set; }
    [Indexed(Sortable = true)]
    public int Age { get; set; }
}

Document, Indexed, Searchable and other features are introduced. For introduction, refer to Github -> document-attribute

Get the operation collection of abstract objects and create indexes

var provider = new RedisConnectionProvider("redis://localhost:6377");
var connection = provider.Connection;
var customers = provider.RedisCollection<Customer>();
connection.CreateIndex(typeof(Customer));

Query data, aggregation operations, etc. need to be based on the index, so be sure to call connection.CreateIndexthe create index first, corresponding to the RediSearch FT.CREATEcommand.

connection.CreateIndex(typeof(Customer)) Repeated execution of creating an index will throw an exception Index already exists. Although connection.Execute("FT.INFO", $"customer-idx")the index information can be obtained by, but the first time the index does not exist will be thrown Unknown Index name. So in actual use, a try-catch wrapping CreateIndexmethod may be required to avoid exceptions.

insert data

var id = customers.Insert(new Customer { FirstName = "Steve", Email = "[email protected]", Age = 1 });
var id2 = customers.Insert(new Customer { FirstName = "FirstName", LastName = "LastName", Email = "[email protected]" });

id, id2 is the key to insert data, if the Prefixes and IdGenerationStrategy of Document are not specified, the default is ULID format {DocumentName}:{Ulid}, such as: `Cust

When inserting data, it should be noted that if the value of a field that is not explicitly specified, such as LastName, is not clearly assigned: customers.Insert(new Customer { FirstName = "Steve", Email = "[email protected]", Age = 1 });, by viewing the data stored in Redis, you can find that the json data stored by the current key does not have a key corresponding to an unspecified field (at this time Query or Aggregations will have some weird bugs). You can assign a zero value to the field or public string LastName { get; set; } = string.Empty;the way you use it when defining the entity according to your needs.

Query data

var customer = customers.Where(x => x.Age == 0).OrderBy(a => a.FirstName).FirstOrDefault();
var customerById = customers.FindById(id);//根据Id查找
var emails = customers.Select(x => x.Email);//仅查询指定字段
var takes = customers.Where(x => x.Age > 0).Take(10);//获取指定条数
var adults = customers.Where(x => x.Age >= 0).Skip(5);//查询偏移

For the judgment of null value, x.FirstName == "" [syntax error] or string.IsNullOrEmpty(x.FirstName) [not supported]. Redis hashes cannot have empty strings, so similar queries should be implemented by means of aggregation Existsoperations

foreach (var agg in customerAggregations.Apply(x => ApplyFunctions.Exists(x.RecordShell.LastName), "LastNameExists"))
{
    Console.WriteLine($"{agg["LastNameExists"]}");
}

Aggregate operation

Pipelining reduces latency by sending multiple requests at the same time. The query and transformation of the results are done on the Redis side.

RecordShell is a structure of remote Index type. RecordShell should only be used inside the aggregation operation pipeline, and has no real value at runtime.

Piece together FirstName and LastName, return FullName

var customerAggregations = provider.AggregationSet<Customer>();
var age = customerAggregations.Average(x => x.RecordShell.Age);
var sets = customerAggregations.Where(a => a.RecordShell.FirstName == "Steve").Apply(x => string.Format("{0} {1}", x.RecordShell.FirstName, x.RecordShell.LastName), "FullName");
foreach (var item in sets)
{
    Console.WriteLine(item["FullName"].ToString());
}

Aggregate grouping

Use the GroupBy method to group and aggregate according to different attributes (single-field grouping and multi-field grouping are supported).

var res = customerAggregations
               .GroupBy(x => x.RecordShell.FirstName)
               .GroupBy(x => x.RecordShell.LastName)
               .ToArray();

var res1 = customerAggregations.GroupBy(x => x.RecordShell.FirstName).CloseGroup().ToArray();

CloseGroup can close the grouping and convert it into a normal aggregation operation, that is, a conversion from GroupedAggregationSet to RedisAggregationSet.

public static RedisAggregationSet<T> CloseGroup<T>(this GroupedAggregationSet<T> source)
{
    return new RedisAggregationSet<T>(source, source.Expression);
}

end

This article is just a simple carding and usability verification of Redis OM .NET usage. For more usage and usage updates, refer to Github

We are in action, new framework, new ecology

Our goals are 自由的, 易用的, 可塑性强的, 功能丰富的, 健壮的.

So we draw on the design concept of Building blocks and are making a new framework MASA Framework. What are its characteristics?

  • Natively supports Dapr and allows replacing Dapr with traditional communication methods
  • Unlimited architecture, monolithic applications, SOA, and microservices are supported
  • Support .Net native framework, reduce learning burden, and insist not to create new wheels except for concepts that must be introduced in specific fields
  • Rich ecological support, in addition to the framework, there are a series of products such as component library, authorization center, configuration center, troubleshooting center, and alarm center
  • Unit test coverage of core code base is 90%+
  • Open source, free, community driven
  • What else? We are waiting for you, let's discuss together

After several months of production project practice, the POC has been completed, and the previous accumulation is currently being refactored into a new open source project

At present, the source code has begun to be synchronized to Github (the documentation site is under planning and will be gradually improved):

MASA.BuildingBlocks

MASA.Contrib

MASA.Utils

MASA.EShop

BlazorComponent

MASA.Blazor

QQ group: 7424099

WeChat group: add technology operation WeChat (MasaStackTechOps), note your intention, invite to join the group

masa_stack_tech_ops.png

​ ------ END ------

About the Author

**Ma Yue: **MASA technical team member.

{{o.name}}
{{m.name}}

Guess you like

Origin my.oschina.net/u/5447363/blog/5393555