Redis OM .NET Redis object mapping framework

Posted by admin101 on Fri, 07 Jan 2022 08:20:33 +0100

Redis OM

Redis OM is an Object Mapping framework officially launched by redis, that is, Object Mapping. It allows developers to operate redis data more simply and conveniently. The data stored in redis is abstracted as Object Mapping and supports object-based redis data persistence and streaming query operations.

Currently, only four development languages are supported:

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

Redis OM .NET

Redis OM .NET is Redis om on net platform depends on stackexchange Redis implementation. With redis OM Net can operate redis data in the way of object operation, away from the operation mode of key/value.
Most queries are supported Neter's favorite LINQ.

Quick start

Install corresponding package

dotnet add package Redis.OM

Redis environment preparation

The Redis environment is installed directly using Docker.

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

The standard official image cannot support Redis OM and needs the support of Redis Modules. The Redis OM core relies on redissearch Module to create indexes and query data. Dependent modules include RediSearch and RedisJSON.
RedisJSON dependency is not necessary, but it lacks corresponding functions, such as model nesting and complex query (only key query is supported)

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; }
}

For the introduction of Document, Indexed, Searchable and other features, please 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 and aggregation operations need to be based on the index, so you must call connection first Createindex creates an index, corresponding to the FT.CREATE command of RediSearch.

connection. If CreateIndex (typeof (customer)) creates an index repeatedly, an exception Index already exists will be thrown. Although you can use connection Execute ("ft.info", $"customer IDX") gets the index information, but the first time the index does not exist, an Unknown Index name will be thrown. Therefore, in actual use, you may need a try catch to wrap the CreateIndex method to avoid exceptions.

insert data

var id = customers.Insert(new Customer { FirstName = "Steve", Email = "xxxx@masa.com", Age = 1 });
var id2 = customers.Insert(new Customer { FirstName = "FirstName", LastName = "LastName", Email = "xxxx@masa.com" });

ID and Id2 are the key s for inserting data. If the Prefixes and IdGenerationStrategy of the Document are not specified, the default is ULID. The format is {DocumentName}:{Ulid}, such as: ` Cust

When inserting data, it should be noted that if the value of the field is not explicitly specified, such as LastName, is not explicitly assigned: customers Insert(new Customer { FirstName = "Steve", Email = " xxxx@masa.com ", age = 1});, 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 (there will be some strange errors in Query or aggregates). You can assign a zero value to the displayed field or use public string LastName {get; set;} when defining the entity according to your needs= string. Empty; The way.

Query data

var customer = customers.Where(x => x.Age == 0).OrderBy(a => a.FirstName).FirstOrDefault();
var customerById = customers.FindById(id);//Find by Id
var emails = customers.Select(x => x.Email);//Query only specified fields
var takes = customers.Where(x => x.Age > 0).Take(10);//Get the specified number of entries
var adults = customers.Where(x => x.Age >= 0).Skip(5);//Query offset

For the judgment of null value, x.FirstName = = "[syntax error] or string Isnullorempty (x.FirstName) [not supported]. Redis hash cannot have empty strings, so similar queries should be implemented through the Exists method of aggregation operation

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

Aggregation operation

Pipelining sends multiple requests at the same time to reduce latency. The query and transformation of the results are completed on the Redis side.

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

Pieced together FirstName and LastName to 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

Through the GroupBy method, group aggregation is carried out 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 turn off grouping and convert to 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);
}

ending

This article is only for redis OM Net usage and usability verification.
More usage and usage update references Github

We are moving towards a new framework and a new ecology

Our goal is free, easy to use, flexible, functional and robust.

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

  • The native supports Dapr and allows Dapr to be replaced by traditional communication methods
  • The architecture is unlimited, and single applications, SOA and microservices are supported
  • support. Net native framework to reduce the learning burden. In addition to the concepts that must be introduced in specific fields, we insist on not making new wheels
  • Rich ecological support, in addition to the framework, there are a series of products such as component library, permission center, configuration center, troubleshooting center, alarm center and so on
  • The unit test coverage of the core code base is 90%+
  • Open source, free, community driven
  • What else? We're waiting for you to discuss it together

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

At present, the source code has been synchronized to Github (the document 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 the purpose, and invite to join the group

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

Introduction to the author

Ma Yue: member of MASA technical team.

Topics: C# Database Redis Back-end .NET