diff --git a/docs/in-depth/server/db/cosmos-sdk.md b/docs/in-depth/server/db/cosmos-sdk.md new file mode 100644 index 0000000..1d28f8e --- /dev/null +++ b/docs/in-depth/server/db/cosmos-sdk.md @@ -0,0 +1,128 @@ +# Cosmos (SDK) + +Support for Cosmos DB is available in two flavors: + +* via [Entity Framework Core](./cosmos.md) - see [EF Core Azure Cosmos DB Provider](https://learn.microsoft.com/ef/core/providers/cosmos/) +* via the Cosmos DB SDK (this document) - see [the official documentation](https://learn.microsoft.com/azure/cosmos-db/nosql/quickstart-dotnet) + +There are differences between the two providers that impact how you configure the container and the operations that are available. + +Use the [CommunityToolkit.Datasync.Server.CosmosDb](https://www.nuget.org/packages/CommunityToolkit.Datasync.Server.CosmosDb) package to add support for this repository. + +Azure Cosmos DB is a fully managed NoSQL database for high-performance applications of any size or scale. See [Azure Cosmos DB for NoSQL .NET SDK](https://learn.microsoft.com/azure/cosmos-db/nosql/quickstart-dotnet) for information on using Azure Cosmos DB via the SDK. + +!!! info + The Cosmos DB library and sample has been kindly contributed to the community by [@richard-einfinity](https://github.com/richard-einfinity). + +## Set up + +1. Set up the Cosmos Container with a composite index that specifies the `UpdatedAt` and `Id` fields. Composite indices can be added to a container through the Azure portal, ARM, Bicep, Terraform, or within code. Here's an example [bicep](https://learn.microsoft.com/azure/azure-resource-manager/bicep/overview) resource definition that would store all datasync entities in the same container: + + resource container 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2022-05-15' = { + parent: database + name: containerName + properties: { + resource: { + id: containerName + partitionKey: { + paths: [ '/entity' ] + kind: 'Hash' + } + indexingPolicy: { + indexingMode: 'consistent' + includedPaths: [ { path: '/*' } ] + excludedPaths: [ { path: '/_etag/?' } ] + compositeIndexes: [ + [ + { path: '/updatedAt', order: 'ascending' } + { path: '/id', order: 'ascending' } + ] + ] + } + } + } + } + + You must include a composite index for each combination of filters that you require. A "client-side evaluation" exception will be generated (which is turned into a `400 Bad Request` by the server) if you do not have the appropriate composite indices for the request. + + You can also review the [bicep module](https://github.com/CommunityToolkit/Datasync/blob/main/samples/datasync-server-cosmosdb-singlecontainer/infra/resources.bicep) that is used in the sample. + + If you pull a subset of items in the table, ensure you specify all properties involved in the query. + +2. Create an appropriate model that inherits from `CosmosTableData`: + + public class TodoItem : CosmosTableData + { + [Required, MinLength(1)] + public string Title { get; set; } = string.Empty; + + public bool IsComplete { get; set; } + } + +3. In `Program.cs`, configure a `CosmosClient` and add this to the services collection as a singleton: + + CosmosClient cosmosClient = new CosmosClient(connectionString, new CosmosClientOptions() + { + UseSystemTextJsonSerializerWithOptions = new() + { + Converters = + { + new JsonStringEnumConverter(), + new DateTimeOffsetConverter(), + new DateTimeConverter(), + new TimeOnlyConverter(), + new SpatialGeoJsonConverter() + }, + PropertyNamingPolicy = JsonNamingPolicy.CamelCase, + DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull | JsonIgnoreCondition.WhenWritingDefault, + NumberHandling = JsonNumberHandling.AllowNamedFloatingPointLiterals, + ReferenceHandler = ReferenceHandler.Preserve + } + }); + + You can obtain the connection string from the Cosmos resource page within the Azure Portal. + +4. Create an `ICosmosTableOptions` object for each entity you wish to use for datasync purposes. The library provides two implementations: + + * `CosmosSharedTableOptions` stores entities in a single container using a partition key based on the entity name. + * `CosmosSingleTableOptions` stores entities by compressing the ID and partition key into the ID of the entity. + + You can also specify your own implementation for custom logic in determining the partition key and ID. Add the `ICosmosTableOptions` objects to the services collection in `Program.cs`: + + builder.Services.AddSingleton>(new CosmosSharedTableOptions("TodoDb", "TodoContainer")); + builder.Services.AddSingleton>(new CosmosSharedTableOptions("TodoDb", "TodoContainer")); + +5. Add the Cosmos repositories to the services collection within `Program.cs` with the following code: + + builder.Services.AddSingleton(typeof(IRepository<>), typeof(CosmosTableRepository<>)); + builder.Services.AddDatasyncServices(); + +6. Create a controller for each datasync entity: + + [Route("tables/[controller]")] + public class TodoItemController : TableController + { + public TodoItemController(IRepository repository) : base(repository) + { + } + } + +You may add other settings to the repository to enable access control providers, logging, and other advanced features. For more information, see the [documentation on the TableController](../index.md#table-controller-options). + +## Avoid Client-side evaluations + +When constructing a query within a client, avoid the following: + +* Math operations such as division, multiplication, floor, ceiling, and round. +* Accessing date/time components such as year, day, or month. +* The use of DateOnly and TimeOnly types. + +These are not supported by the query provider for Cosmos DB. Using them will result in a client-side evaluation. Client-side evaluations are not supported and will result in a `400 Bad Request` or `500 Internal Server Error`. + +## Support and further information + +Azure Cosmos DB is supported in the `Microsoft.AspNetCore.Datasync.CosmosDb` NuGet package since v9.0.1. For more information, review the following links: + +* [Azure Cosmos DB .NET SDK](https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/quickstart-dotnet) documentation. +* [Cosmos DB index policy](https://learn.microsoft.com/azure/cosmos-db/index-policy) documentation. +* [Cosmos DB single container reference sample](https://github.com/CommunityToolkit/Datasync/tree/main/samples/datasync-server-cosmosdb-singlecontainer) \ No newline at end of file diff --git a/docs/in-depth/server/db/cosmos.md b/docs/in-depth/server/db/cosmos.md index ebb89bb..4df1af5 100644 --- a/docs/in-depth/server/db/cosmos.md +++ b/docs/in-depth/server/db/cosmos.md @@ -1,6 +1,13 @@ -# Cosmos (via EF Core) +# Cosmos (EF Core) -Cosmos is configured via Entity Framework Core. Use the [CommunityToolkit.Datasync.Server.EntityFrameworkCore](https://www.nuget.org/packages/CommunityToolkit.Datasync.Server.EntityFrameworkCore) package to add support for this repository. +Support for Cosmos DB is available in two flavors: + +* via Entity Framework Core (this document) - see [EF Core Azure Cosmos DB Provider](https://learn.microsoft.com/ef/core/providers/cosmos/) +* via [the Cosmos DB SDK](./cosmos-sdk.md) - see [the official documentation](https://learn.microsoft.com/azure/cosmos-db/nosql/quickstart-dotnet) + +There are differences between the two providers that impact how you configure the container and the operations that are available. + +Cosmos DB is configured via Entity Framework Core. Use the [CommunityToolkit.Datasync.Server.EntityFrameworkCore](https://www.nuget.org/packages/CommunityToolkit.Datasync.Server.EntityFrameworkCore) package to add support for this repository. Azure Cosmos DB is a fully managed NoSQL database for high-performance applications of any size or scale. See [Azure Cosmos DB Provider](https://learn.microsoft.com/ef/core/providers/cosmos/) for information on using Azure Cosmos DB with Entity Framework Core. When using Azure Cosmos DB with the Datasync Community Toolkit: @@ -15,34 +22,18 @@ Azure Cosmos DB is a fully managed NoSQL database for high-performance applicati resource: { id: 'TodoItems' partitionKey: { - paths: [ - '/Id' - ] + paths: [ '/Id' ] kind: 'Hash' } indexingPolicy: { indexingMode: 'consistent' automatic: true - includedPaths: [ - { - path: '/*' - } - ] - excludedPaths: [ - { - path: '/"_etag"/?' - } - ] + includedPaths: [ { path: '/*' } ] + excludedPaths: [ { path: '/"_etag"/?' } ] compositeIndexes: [ [ - { - path: '/UpdatedAt' - order: 'ascending' - } - { - path: '/Id' - order: 'ascending' - } + { path: '/UpdatedAt', order: 'ascending' } + { path: '/Id', order: 'ascending' } ] ] } diff --git a/docs/in-depth/server/index.md b/docs/in-depth/server/index.md index 59628bf..b2f79c1 100644 --- a/docs/in-depth/server/index.md +++ b/docs/in-depth/server/index.md @@ -19,7 +19,7 @@ The datasync service support a number of backend database servers, and allows fo Default repository implementations are provided for Entity Framework Core, LiteDB, an in-memory store, and an Automapper store. For specific database support, see the following: -* [Azure Cosmos DB](./db/cosmos.md) +* Azure Cosmos DB ([EFCore](./db/cosmos.md) and [SDK](./db/cosmos-sdk.md)) * [Azure SQL and SQL Server](./db/azuresql.md) * [In Memory Datastore](./db/in-memory.md) * [LiteDb](./db/litedb.md) @@ -60,9 +60,13 @@ Ensure you map the controllers when setting up your HTTP middleware pipeline. Y All model classes must implement `ITableData`. Each repository type has an abstract class that implements `ITableData` and provides additional functionality to the repository. For example, the Entity Framework Core repository provides: -* `SqliteEntityTableData` for Sqlite. +* `InMemoryTableData` for an in-memory data store. +* `LiteDbTableData` for a LiteDb based store. * `CosmosEntityTableData` for Cosmos Db support via EF Core. -* `EntityTableData` for other EF-Core based database connections. +* `CosmosTableData` for Cosmos Db support via the Cosmos DB SDK. +* `EntityTableData` for most EF-Core based database providers. +* `MongoTableData` for Mongo DB (via the MongoDB SDK). +* `SqliteEntityTableData` for Sqlite. A typical "TodoItem" entity for PostgreSQL would look like this: diff --git a/mkdocs.shared.yml b/mkdocs.shared.yml index 86e3517..b19d0e0 100644 --- a/mkdocs.shared.yml +++ b/mkdocs.shared.yml @@ -41,6 +41,7 @@ nav: - Databases: - Azure SQL: in-depth/server/db/azuresql.md - "CosmosDB (EFCore)": in-depth/server/db/cosmos.md + - "CosmosDB (SDK)": in-depth/server/db/cosmos-sdk.md - In Memory: in-depth/server/db/in-memory.md - LiteDb: in-depth/server/db/litedb.md - MongoDb: in-depth/server/db/mongodb.md