{"id":14977735,"url":"https://github.com/redis/redis-om-dotnet","last_synced_at":"2025-05-14T04:08:29.636Z","repository":{"id":37859254,"uuid":"412586952","full_name":"redis/redis-om-dotnet","owner":"redis","description":"Object mapping, and more, for Redis and .NET","archived":false,"fork":false,"pushed_at":"2025-04-30T22:41:33.000Z","size":1829,"stargazers_count":497,"open_issues_count":43,"forks_count":81,"subscribers_count":24,"default_branch":"main","last_synced_at":"2025-05-08T00:13:39.545Z","etag":null,"topics":["dotnet","linq","redis"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/redis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-10-01T19:01:05.000Z","updated_at":"2025-05-04T09:19:05.000Z","dependencies_parsed_at":"2023-02-09T17:02:32.978Z","dependency_job_id":"5d66e5c7-333b-4c1e-92e0-739f7dad0a23","html_url":"https://github.com/redis/redis-om-dotnet","commit_stats":{"total_commits":189,"total_committers":34,"mean_commits":"5.5588235294117645","dds":0.3386243386243386,"last_synced_commit":"ef7135e3bd110f2982364efbe9559d7c86aeff10"},"previous_names":[],"tags_count":34,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis%2Fredis-om-dotnet","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis%2Fredis-om-dotnet/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis%2Fredis-om-dotnet/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redis%2Fredis-om-dotnet/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/redis","download_url":"https://codeload.github.com/redis/redis-om-dotnet/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253754521,"owners_count":21958877,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dotnet","linq","redis"],"created_at":"2024-09-24T13:56:14.259Z","updated_at":"2025-05-14T04:08:29.618Z","avatar_url":"https://github.com/redis.png","language":"C#","funding_links":[],"categories":["C\\#"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cbr/\u003e\n  \u003cbr/\u003e\n  \u003cimg width=\"360\" src=\"images/logo.svg\" alt=\"Redis OM\" /\u003e\n  \u003cbr/\u003e\n  \u003cbr/\u003e\n\u003c/div\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cp align=\"center\"\u003e\n        Object mapping, and more, for Redis and .NET\n    \u003c/p\u003e\n\u003c/p\u003e\n\n---\n\n[![NuGet](http://img.shields.io/nuget/v/Redis.OM.svg?style=flat-square)](https://www.nuget.org/packages/Redis.OM/)\n[![License][license-image]][license-url]\n[![Build Status][ci-svg]][ci-url]\n\n\n\n**Redis OM .NET** makes it easy to model Redis data in your .NET Applications.\n\n**Redis OM .NET** | [Redis OM Node.js](https://github.com/redis/redis-om-node) | [Redis OM Spring](https://github.com/redis/redis-om-spring) | [Redis OM Python](https://github.com/redis/redis-om-python)\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003cstrong\u003eTable of contents\u003c/strong\u003e\u003c/summary\u003e\n\n\u003c!-- START doctoc generated TOC please keep comment here to allow auto update --\u003e\n\u003c!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE --\u003e\n\n- [💡 Why Redis OM?](#-why-redis-om)\n- [💻 Installation](#-installation)\n- [🏁 Getting started](#-getting-started)\n  - [Starting Redis](#starting-redis)\n  - [📇 Modeling your domain (and indexing it!)](#-modeling-your-domain-and-indexing-it)\n  - [🔑 Keys and Ids](#-keys-and-ids)\n  - [🔎 Querying](#-querying)\n  - [🖩 Aggregations](#-aggregations)\n- [📚 Documentation](#-documentation)\n- [⛏️ Troubleshooting](#-troubleshooting)\n- [✨ Redis Stack](#-redis-stack)\n  - [Why this is important](#why-this-is-important)\n  - [So how do you get Redis Stack?](#so-how-do-you-get-redis-stack)\n- [❤️ Contributing](#-contributing)\n- [Connecting to Azure Managed Redis with EntraId](#connecting-to-azure-managed-redis-with-entraid)\n  - [Prerequisites](#prerequisites)\n  - [Connecting with EntraId](#connecting-with-entraid)\n- [❤️ Our Contributors](#-our-contributors)\n\n\u003c!-- END doctoc generated TOC please keep comment here to allow auto update --\u003e\n\n\u003c/details\u003e\n\n## 💡 Why Redis OM?\n\nRedis OM provides high-level abstractions for using Redis in .NET, making it easy to model and query your Redis domain objects.\n\nRedis OM contains the following features:\n\n* Declarative object mapping for Redis objects\n* Declarative secondary-index generation\n* Fluent APIs for querying Redis\n* Fluent APIs for performing Redis aggregations\n\n## 💻 Installation\n\nUsing the dotnet cli, run:\n\n```text\ndotnet add package Redis.OM\n```\n\n## 🏁 Getting started\n\n### Starting Redis\n\nBefore writing any code you'll need a Redis instance with the appropriate Redis modules! The quickest way to get this is with Docker:\n\n```sh\ndocker run -p 6379:6379 -p 8001:8001 redis/redis-stack\n```\n\nThis launches the [redis-stack](https://redis.io/docs/stack/) an extension of Redis that adds all manner of modern data structures to Redis. You'll also notice that if you open up http://localhost:8001 you'll have access to the redis-insight GUI, a GUI you can use to visualize and work with your data in Redis.\n\n### 📇 Modeling your domain (and indexing it!)\n\nWith Redis OM, you can model your data and declare indexes with minimal code. For example, here's how we might model a customer object:\n\n```csharp\n[Document(StorageType = StorageType.Json)]\npublic class Customer\n{\n   [Indexed] public string FirstName { get; set; }\n   [Indexed] public string LastName { get; set; }\n   public string Email { get; set; }\n   [Indexed(Sortable = true)] public int Age { get; set; }\n   [Indexed] public string[] NickNames {get; set;}\n}\n```\n\nNotice that we've applied the `Document` attribute to this class. We've also specified that certain fields should be `Indexed`.\n\nNow we need to create the Redis index. So we'll connect to Redis and then call `CreateIndex` on an `IRedisConnection`:\n\n\n```csharp\nvar provider = new RedisConnectionProvider(\"redis://localhost:6379\");\nprovider.Connection.CreateIndex(typeof(Customer));\n```\n\nRedis OM provides limited support for schema migration at this time. You can check if the index definition in Redis matches your current index definition using the `IsIndexCurrent` method on the `RedisConnection`. Then you may use that output to determine when to re-create your indexes when your types change. An example implementation of this would look like:\n\n```csharp\nvar provider = new RedisConnectionProvider(\"redis://localhost:6379\");\nvar definition = provider.Connection.GetIndexInfo(typeof(Customer));\n\nif (!provider.Connection.IsIndexCurrent(typeof(Customer)))\n{\n    provider.Connection.DropIndex(typeof(Customer));\n    provider.Connection.CreateIndex(typeof(Customer));\n}\n```\n\n\n### Indexing Embedded Documents\n\nThere are two methods for indexing embedded documents with Redis.OM, an embedded document is a complex object, e.g. if our `Customer` model had an `Address` property with the following model:\n\n```csharp\n[Document(IndexName = \"address-idx\", StorageType = StorageType.Json)]\npublic partial class Address\n{\n    public string StreetName { get; set; }\n    public string ZipCode { get; set; }\n    [Indexed] public string City { get; set; }\n    [Indexed] public string State { get; set; }\n    [Indexed(CascadeDepth = 1)] public Address ForwardingAddress { get; set; }\n    [Indexed] public GeoLoc Location { get; set; }\n    [Indexed] public int HouseNumber { get; set; }\n}\n```\n\n#### Index By JSON Path\n\nYou can index fields by JSON path, in the top level model, in this case `Customer` you can decorate the `Address` property with an `Indexed` and/or `Searchable` attribute, specifying the JSON path to the desired field:\n\n```csharp\n[Document(StorageType = StorageType.Json)]\npublic class Customer\n{\n   [Indexed] public string FirstName { get; set; }\n   [Indexed] public string LastName { get; set; }\n   public string Email { get; set; }\n   [Indexed(Sortable = true)] public int Age { get; set; }\n   [Indexed] public string[] NickNames {get; set;}\n   [Indexed(JsonPath = \"$.ZipCode\")]\n   [Searchable(JsonPath = \"$.StreetAddress\")]\n   public Address Address {get; set;}\n}\n```\n\n##### Indexing Arrays of Objects\n\nThis methodology can also be used for indexing string and string-like value-types within objects within Arrays and Lists, so for example if we had an array of Addresses, and we wanted to index the cities within those addresses we could do so with the following\n\n```cs\n[Indexed(JsonPath = \"$.City\")]\npublic Address[] Addresses { get; set; }\n```\n\nThose Cities can then be queried with an `Any` predicate within the main `Where` clause.\n\n```cs\ncollection.Where(c=\u003ec.Addresses.Any(a=\u003ea.City == \"Satellite Beach\"))\n```\n\n###### Limitations\n\nThe way Redis indexes fields within a collection of embedded objects does not allow multiple predictates to be specified to a given document e.g.\n\n```cs\ncollection.Where(c=\u003ec.Addresses.Any(a=\u003ea.City == \"Satellite Beach\" \u0026\u0026 a.ZipCode == \"32937))\n```\n\nIn the above case the query can only check if the Addresses collection contains an entry that is `Satellite Beach`, and Contains an entry that has a zip code of `32937`, rather than an entry that has both the city of `Satellite Beach` and a  zip code of `32937\n\n#### Cascading Index\n\nAlternatively, you can also embedded models by cascading indexes. In this instance you'd simply decorate the property with `Indexed` and set the `CascadeDepth` to whatever to however may levels you want the model to cascade for. The default is 0, so if `CascadeDepth` is not set, indexing an object will be a no-op:\n\n```csharp\n[Document(StorageType = StorageType.Json)]\npublic class Customer\n{\n   [Indexed] public string FirstName { get; set; }\n   [Indexed] public string LastName { get; set; }\n   public string Email { get; set; }\n   [Indexed(Sortable = true)] public int Age { get; set; }\n   [Indexed] public string[] NickNames {get; set;}\n   [Indexed(CascadeDepth = 2)]\n   public Address Address {get; set;}\n}\n```\n\nIn the above case, all indexed/searchable fields in Address will be indexed down 2 levels, so the `ForwardingAddress` field in `Address` will also be indexed.\n\nOnce the index is created, we can:\n\n* Insert Customer objects into Redis\n* Get a Customer object by ID from Redis\n* Query Customers from Redis\n* Run aggregations on Customers in Redis\n\nLet's see how!\n\n### Indexing DateTimes\n\nAs of version 0.4.0, all DateTime objects are indexed as numerics, and they are inserted as numerics into JSON documents. Because of this, you can query them as if they were numerics!\n\n### 🔑 Keys and Ids\n\n#### ULIDs and strings\n\nIds are unique per object, and are used as part of key generation for the primary index in Redis. The natively supported Id type in Redis OM is the [ULID][ulid-url]. You can bind ids to your model, by explicitly decorating your Id field with the `RedisIdField` attribute:\n\n```csharp\n[Document(StorageType = StorageType.Json)]\npublic class Customer\n{\n    [RedisIdField] public Ulid Id { get; set; }\n    [Indexed] public string FirstName { get; set; }\n    [Indexed] public string LastName { get; set; }\n    public string Email { get; set; }\n    [Indexed(Sortable = true)] public int Age { get; set; }\n    [Indexed] public string[] NickNames { get; set; }\n}\n```\n\nWhen you call `Set` on the `RedisConnection` or call `Insert` in the `RedisCollection`, to insert your object into Redis, Redis OM will automatically set the id  for you and you will be able to access it in the object. If the `Id` type is a string, and there is no explicitly overriding IdGenerationStrategy on the object, the ULID for the object will bind to the string.\n\n#### Other types of ids\n\nRedis OM also supports other types of ids, ids must either be strings or value types (e.g. ints, longs, GUIDs etc. . .), if you want a non-ULID id type, you must either set the id on each object prior to insertion, or you must register an `IIdGenerationStrategy` with the `DocumentAttribute` class.\n\n##### Register IIdGenerationStrategy\n\nTo Register an `IIdGenerationStrategy` with the `DocumentAttribute` class, simply call `DocumentAttribute.RegisterIdGenerationStrategy` passing in the strategy name, and the implementation of `IIdGenerationStrategy` you want to use. Let's say for example you had the `StaticIncrementStrategy`, which maintains a static counter in memory, and increments ids based off that counter:\n\n```csharp\npublic class StaticIncrementStrategy : IIdGenerationStrategy\n{\n    public static int Current = 0;\n    public string GenerateId()\n    {\n        return (Current++).ToString();\n    }\n}\n```\n\nYou would then register that strategy with Redis.OM like so:\n\n```csharp\nDocumentAttribute.RegisterIdGenerationStrategy(nameof(StaticIncrementStrategy), new StaticIncrementStrategy());\n```\n\nThen, when you want to use that strategy for generating the Ids of a document, you can simply set the IdGenerationStrategy of your document attribute to the name of the strategy.\n\n```csharp\n[Document(IdGenerationStrategyName = nameof(StaticIncrementStrategy))]\npublic class ObjectWithCustomIdGenerationStrategy\n{\n    [RedisIdField] public string Id { get; set; }\n}\n```\n\n#### Key Names\n\nThe key names are, by default, the fully qualified class name of the object, followed by a colon, followed by the `Id`. For example, there is a Person class in the Unit Test project, an example id of that person class would be `Redis.OM.Unit.Tests.RediSearchTests.Person:01FTHAF0D1EKSN0XG67HYG36GZ`, because `Redis.OM.Unit.Tests.RediSearchTests.Person` is the fully qualified class name, and `01FTHAF0D1EKSN0XG67HYG36GZ` is the ULID (the default id type). If you want to change the prefix (the fully qualified class name), you can change that in the `DocumentAttribute` by setting the `Prefixes` property, which is an array of strings e.g.\n\n```csharp\n[Document(Prefixes = new []{\"Person\"})]\npublic class Person\n```\n\n\u003e Note: At this time, Redis.OM will only use the first prefix in the prefix list as the prefix when creating a key name. However, when an index is created, it will be created on all prefixes enumerated in the Prefixes property\n\n### 🔎 Querying\n\nWe can query our domain using expressions in LINQ, like so:\n\n```csharp\nvar customers = provider.RedisCollection\u003cCustomer\u003e();\n\n// Insert customer\ncustomers.Insert(new Customer()\n{\n    FirstName = \"James\",\n    LastName = \"Bond\",\n    Age = 68,\n    Email = \"bondjamesbond@email.com\"\n});\n\n// Find all customers whose last name is \"Bond\"\ncustomers.Where(x =\u003e x.LastName == \"Bond\");\n\n// Find all customers whose last name is Bond OR whose age is greater than 65\ncustomers.Where(x =\u003e x.LastName == \"Bond\" || x.Age \u003e 65);\n\n// Find all customers whose last name is Bond AND whose first name is James\ncustomers.Where(x =\u003e x.LastName == \"Bond\" \u0026\u0026 x.FirstName == \"James\");\n\n// Find all customers with the nickname of Jim\ncustomers.Where(x=\u003ex.NickNames.Contains(\"Jim\"));\n```\n\n#### Using Raw Queries\n\nFor advanced scenarios where you need direct control over the filter syntax, Redis OM provides a Raw extension method that lets you write the query filter using the Redis Search query syntax directly:\n\n```csharp\n// Use raw query to find customers named Bond with exact tag matching\nvar results = customers.Raw(\"@LastName:{Bond}\").ToList();\n```\n\n**Important**: The Raw method ONLY sets the filter portion of the query. For all other query parameters such as sorting, pagination, etc., you should continue to use the LINQ methods:\n\n```csharp\n// Raw for filter + OrderBy for sorting\nvar results = customers.Raw(\"@LastName:{Bond}\")\n    .OrderBy(c =\u003e c.Age)\n    .ToList();\n\n// Raw for filter + Skip/Take for pagination\nvar results = customers.Raw(\"@Age:[30 70]\")\n    .Skip(10)\n    .Take(5)\n    .ToList();\n```\n\nThis is also true for aggregations, where Raw only sets the initial filter, and you should use the full aggregation API for the rest of the pipeline:\n\n```csharp\nvar aggSet = customers.AggregationSet();\n\n// Raw sets ONLY the filter, then use the aggregation API for operations\nvar results = aggSet.Raw(\"@Age:[30 70]\")\n    .GroupBy(x =\u003e x.RecordShell.LastName)\n    .Average(x =\u003e x.RecordShell.Age)\n    .ToList();\n```\n\nFor more details on the Redis Search query syntax for filters, refer to the [RediSearch Query Syntax Documentation](https://redis.io/docs/stack/search/reference/query_syntax/).\n\n### Vectors\n\nRedis OM .NET also supports storing and querying Vectors stored in Redis. \n\nA `Vector\u003cT\u003e` is a representation of an object that can be transformed into a vector by a Vectorizer.\n\nA `VectorizerAttribute` is the abstract class you use to decorate your Vector fields, it is responsible for defining the logic to convert the object's that `Vector\u003cT\u003e` is a container for into actual vector embeddings needed. In the package `Redis.OM.Vectorizers` we provide vectorizers for HuggingFace, OpenAI, and AzureOpenAI to allow you to easily integrate them into your workflows.\n\n#### Define a Vector in your Model.\n\nTo define a vector in your model, simply decorate a `Vector\u003cT\u003e` field with an `Indexed` attribute which defines the algorithm and algorithmic parameters and a `Vectorizer` attribute which defines the shape of the vectors, (in this case we'll use OpenAI):\n\n```cs\n[Document(StorageType = StorageType.Json)]\npublic class OpenAICompletionResponse\n{\n    [RedisIdField]\n    public string Id { get; set; }\n\n    [Indexed(DistanceMetric = DistanceMetric.COSINE, Algorithm = VectorAlgorithm.HNSW, M = 16)]\n    [OpenAIVectorizer]\n    public Vector\u003cstring\u003e Prompt { get; set; }\n\n    public string Response { get; set; }\n\n    [Indexed]\n    public string Language { get; set; }\n    \n    [Indexed]\n    public DateTime TimeStamp { get; set; }\n}\n```\n\n#### Insert Vectors into Redis\n\nWith the vector defined in our model, all we need to do is create Vectors of the generic type, and insert them with our model. Using our `RedisCollection`, you can do this by simply using `Insert`:\n\n```cs\nvar collection = _provider.RedisCollection\u003cOpenAICompletionResponse\u003e();\nvar completionResult = new OpenAICompletionResponse\n{\n    Language = \"en_us\", \n    Prompt = Vector.Of(\"What is the Capital of France?\"), \n    Response = \"Paris\", \n    TimeStamp = DateTime.Now - TimeSpan.FromHours(3)\n};\ncollection.Insert(completionResult);\n```\n\nThe Vectorizer will manage the embedding generation for you without you having to intervene.\n\n#### Query Vectors in Redis\n\nTo query vector fields in Redis, all you need to do is use the `VectorRange` method on a vector within our normal LINQ queries, and/or use the `NearestNeighbors` with whatever other filters you want to use, here's some examples:\n\n```cs\nvar prompt = \"What really is the Capital of France?\";\n\n// simple vector range, find first within .15\nvar result = collection.First(x =\u003e x.Prompt.VectorRange(prompt, .15));\n\n// simple nearest neighbors query, finds first nearest neighbor\nresult = collection.NearestNeighbors(x =\u003e x.Prompt, 1, prompt).First();\n\n// hybrid query, pre-filters result set for english responses, then runs a nearest neighbors search.\nresult = collection.Where(x=\u003ex.Language == \"en_us\").NearestNeighbors(x =\u003e x.Prompt, 1, prompt).First();\n\n// hybrid query, pre-filters responses newer than 4 hours, and finds first result within .15\nvar ts = DateTimeOffset.Now - TimeSpan.FromHours(4);\nresult = collection.First(x=\u003ex.TimeStamp \u003e ts \u0026\u0026 x.Prompt.VectorRange(prompt, .15));\n```\n\n#### What Happens to the Embeddings?\n\nWith Redis OM, the embeddings can be completely transparent to you, they are generated and bound to the `Vector\u003cT\u003e` when you query/insert your vectors. If however you needed your embedding after the insertion/Query, they are available at `Vector\u003cT\u003e.Embedding`, and be queried either as the raw bytes, as an array of doubles or as an array of floats (depending on your vectorizer).\n\n#### Configuration\n\nThe Vectorizers provided by the `Redis.OM.Vectorizers` package have some configuration parameters that it will pull in either from your `appsettings.json` file, or your environment variables (with your appsettings taking precedence).\n\n| Configuration Parameter            | Description                                   |\n|--------------------------------    |-----------------------------------------------|\n| REDIS_OM_HF_TOKEN                  | HuggingFace Authorization token.              |\n| REDIS_OM_OAI_TOKEN                 | OpenAI Authorization token                    |\n| REDIS_OM_OAI_API_URL               | OpenAI URL                                    |\n| REDIS_OM_AZURE_OAI_TOKEN           | Azure OpenAI api key                          |\n| REDIS_OM_AZURE_OAI_RESOURCE_NAME   | Azure resource name                           |\n| REDIS_OM_AZURE_OAI_DEPLOYMENT_NAME | Azure deployment                              |\n\n### Semantic Caching\n\nRedis OM also provides the ability to use Semantic Caching, as well as providers for OpenAI, HuggingFace, and Azure OpenAI to perform semantic caching. To use a Semantic Cache, simply pull one out of the RedisConnectionProvider and use `Store` to insert items, and `GetSimilar` to retrieve items. For example:\n\n```cs\nvar cache = _provider.OpenAISemanticCache(token, threshold: .15);\ncache.Store(\"What is the capital of France?\", \"Paris\");\nvar res = cache.GetSimilar(\"What really is the capital of France?\").First();\n```\n\n### ML.NET Based Vectorizers\n\nWe also provide the packages `Redis.OM.Vectorizers.ResNet18` and `Redis.OM.Vectorizers.AllMiniLML6V2` which have embedded models / ML Pipelines in them to\nallow you to easily Vectorize Images and Sentences respectively without the need to depend on an external API.\n\n### 🖩 Aggregations\n\nWe can also run aggregations on the customer object, again using expressions in LINQ:\n\n```csharp\n// Get our average customer age\ncustomerAggregations.Average(x =\u003e x.RecordShell.Age);\n\n// Format customer full names\ncustomerAggregations.Apply(x =\u003e string.Format(\"{0} {1}\", x.RecordShell.FirstName, x.RecordShell.LastName),\n      \"FullName\");\n\n// Get each customer's distance from the Mall of America\ncustomerAggregations.Apply(x =\u003e ApplyFunctions.GeoDistance(x.RecordShell.Home, -93.241786, 44.853816),\n      \"DistanceToMall\");\n```\n\n## 📚 Documentation\n\nThis README just scratches the surface. You can find a full tutorial on the [redis.io](https://redis.io/learn/develop/dotnet/redis-om-dotnet/add-and-retrieve-objects). All the summary docs for this library can be found on the repo's [github page](https://redis.github.io/redis-om-dotnet/).\n\n## ⛏️ Troubleshooting\n\nIf you run into trouble or have any questions, we're here to help!\n\nFirst, check the [FAQ](docs/faq.md). If you don't find the answer there,\nhit us up on the [Redis Discord Server](http://discord.gg/redis).\n\n## ✨ Redis Stack\n\nRedis OM can be used with regular Redis for Object mapping and getting objects by their IDs. For more advanced features like indexing, querying, and aggregation, Redis OM is dependent on the [**Redis Stack**](https://redis.io/docs/stack/) platform, a collection of modules that extend Redis.\n\n### Why this is important\n\nWithout Redis Stack, you can still use Redis OM to create declarative models backed by Redis.\n\nWe'll store your model data in Redis as Hashes, and you can retrieve models using their primary keys.\n\nSo, what won't work without Redis Stack?\n\n1. You won't be able to nest models inside each other.\n2. You won't be able to use our expressive queries to find object -- you'll only be able to query by primary key.\n\n### So how do you get Redis Stack?\n\nYou can use Redis Stack with your self-hosted Redis deployment. Just follow the instructions for [Installing Redis Stack](https://redis.io/docs/stack/get-started/install/).\n\nDon't want to run Redis yourself? Redis Stack is also available on Redis Cloud. [Get started here](https://redis.com/try-free/).\n\n## ❤️ Contributing\n\nWe'd love your contributions! If you want to contribute please read our [Contributing](CONTRIBUTING.md) document.\n\n## Connecting to Azure Managed Redis with EntraId\n\nRedis OM .NET supports connecting to Azure Managed Redis instances using EntraId (formerly Azure AD) authentication. This allows you to securely connect to your Azure Redis instance without embedding connection secrets in your code.\n\n### Prerequisites\n\n1. Install the required NuGet packages:\n   ```\n   dotnet add package Microsoft.Azure.StackExchangeRedis\n   dotnet add package Azure.Identity\n   ```\n\n2. Configure your Azure Redis instance to use EntraId authentication\n\n### Connecting with EntraId\n\n```csharp\nusing Azure.Identity;\nusing Redis.OM;\nusing StackExchange.Redis;\n\n// Create configuration options for your Azure Redis endpoint\n// Standard format for Azure Managed Redis: your-instance-name.region.redis.azure.net:10000\nConfigurationOptions options = new ConfigurationOptions\n{\n    EndPoints = { \"your-instance-name.region.redis.azure.net:10000\" }\n};\n\n// Configure for Azure with DefaultAzureCredential\nawait options.ConfigureForAzureWithTokenCredentialAsync(new DefaultAzureCredential());\n\n// Connect to Redis using EntraId authentication\nvar muxer = ConnectionMultiplexer.Connect(options);\n\n// Create Redis OM connection provider using the authenticated connection\nvar provider = new RedisConnectionProvider(muxer);\n\n// Define a model for Redis OM\n[Document(StorageType = StorageType.Json)]\npublic class Customer\n{\n    [RedisIdField] public string Id { get; set; }\n    [Indexed] public string Name { get; set; }\n    [Indexed] public string Email { get; set; }\n    [Indexed(Sortable = true)] public int Age { get; set; }\n}\n\n// Create index if it doesn't exist\nawait provider.Connection.CreateIndexAsync(typeof(Customer));\n\n// Get a Redis collection for your model\nvar customers = provider.RedisCollection\u003cCustomer\u003e();\n\n// Insert a new customer\nawait customers.InsertAsync(new Customer \n{\n    Name = \"Jane Smith\",\n    Email = \"jane@example.com\",\n    Age = 32\n});\n\n// Query customers\nvar youngCustomers = await customers.Where(c =\u003e c.Age \u003c 35).ToListAsync();\nforeach (var customer in youngCustomers)\n{\n    Console.WriteLine($\"Name: {customer.Name}, Email: {customer.Email}, Age: {customer.Age}\");\n}\n```\n\nThe `DefaultAzureCredential` class will automatically try various authentication methods, including:\n- Environment variables\n- Managed Identity\n- Visual Studio credentials\n- Azure CLI credentials\n- Interactive browser login\n\nThis approach is particularly useful for services deployed to Azure, as it allows you to use Managed Identity without hardcoding any secrets.\n\n## ❤️ Our Contributors\n\n* [@slorello89](https://github.com/slorello89)\n* [@banker](https://github.com/banker)\n* [@simonprickett](https://github.com/simonprickett)\n* [@BenShapira](https://github.com/BenShapira)\n* [@satish860](https://github.com/satish860)\n* [@dracco1993](https://github.com/dracco1993)\n* [@ecortese](https://github.com/ecortese)\n* [@DanJRWalsh](https://github.com/DanJRWalsh)\n* [@baldutech](https://github.com/baldutech)\n* [@shacharPash](https://github.com/shacharPash)\n* [@frostshoxx](https://github.com/frostshoxx)\n* [@berviantoleo](https://github.com/berviantoleo)\n* [@AmirEsdeki](https://github.com/AmirEsdeki)\n* [@Zulander1](https://github.com/zulander1)\n* [@Jeevananthan](https://github.com/Jeevananthan-23)\n* [@mariusmuntean](https://github.com/mariusmuntean)\n* [@jcreus1](https://github.com/jcreus1)\n* [@JuliusMikkela](https://github.com/JuliusMikkela)\n* [@imansafari1991](https://github.com/imansafari1991)\n* [@AndersenGans](https://github.com/AndersenGans)\n* [@mdrakib](https://github.com/mdrakib)\n* [@jrpavoncello](https://github.com/jrpavoncello)\n* [@axnetg](https://github.com/axnetg)\n* [@abbottdev](https://github.com/abbottdev)\n* [@PrudiusVladislav](https://github.com/PrudiusVladislav)\n* [@CormacLennon](https://github.com/CormacLennon)\n* [@ahmedisam99](https://github.com/ahmedisam99)\n* [@kirollosonsi](https://github.com/kirollosonsi)\n* [@tgmoore](https://github.com/tgmoore)\n* [@mfaulcon](https://github.com/mfaulcon)\n\n\u003c!-- Logo --\u003e\n[Logo]: images/logo.svg\n\n\u003c!-- Badges --\u003e\n\n[ci-svg]: https://github.com/redis-developer/redis-developer-dotnet/actions/workflows/dotnet-core.yml/badge.svg\n[ci-url]: https://github.com/redis-developer/redis-developer-dotnet/actions/workflows/dotnet-core.yml\n[license-image]: https://img.shields.io/badge/License-MIT-red.svg\n[license-url]: LICENSE\n\n\u003c!-- Links --\u003e\n\n[redis-developer-website]: https://developer.redis.com\n[redis-om-js]: https://github.com/redis-developer/redis-om-node\n[redis-om-python]: https://github.com/redis-developer/redis-om-python\n[redis-om-spring]: https://github.com/redis-developer/redis-om-spring\n[redisearch-url]: https://oss.redis.com/redisearch/\n[redis-json-url]: https://oss.redis.com/redisjson/\n[pydantic-url]: https://github.com/samuelcolvin/pydantic\n[ulid-url]: https://github.com/ulid/spec\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredis%2Fredis-om-dotnet","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fredis%2Fredis-om-dotnet","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredis%2Fredis-om-dotnet/lists"}