Cirreum.Persistence.NoSql
1.0.11
dotnet add package Cirreum.Persistence.NoSql --version 1.0.11
NuGet\Install-Package Cirreum.Persistence.NoSql -Version 1.0.11
<PackageReference Include="Cirreum.Persistence.NoSql" Version="1.0.11" />
<PackageVersion Include="Cirreum.Persistence.NoSql" Version="1.0.11" />
<PackageReference Include="Cirreum.Persistence.NoSql" />
paket add Cirreum.Persistence.NoSql --version 1.0.11
#r "nuget: Cirreum.Persistence.NoSql, 1.0.11"
#:package Cirreum.Persistence.NoSql@1.0.11
#addin nuget:?package=Cirreum.Persistence.NoSql&version=1.0.11
#tool nuget:?package=Cirreum.Persistence.NoSql&version=1.0.11
Cirreum Persistence NoSql Library
A comprehensive .NET persistence NoSql based abstraction library that provides type-safe, feature-rich repository patterns for data access operations without external dependencies. This library offers a clean separation between your domain logic and persistence concerns through well-defined interfaces and base implementations
Overview
The Cirreum Persistence Library contains abstractions and contracts for implementing persistence repositories with support for:
- Entity Management: Base entity types with built-in auditing, soft deletes, ETags, and TTL
- Repository Patterns: Read-only, write-only, batch, and full repository interfaces
- Advanced Querying: Expression-based queries, pagination, and async enumeration
- Partial Updates: Patch operations with expression and path-based targeting
- Soft Deletes: Built-in soft delete and restore capabilities
- Auditing: Automatic tracking of creation, modification, and deletion metadata
- Time Zones: IANA timezone support for audit fields
- Concurrency Control: ETag-based optimistic concurrency
- Time-to-Live: Automatic entity expiration support
Core Interfaces
Entity Interfaces
IEntity: Base entity contract with Id, EntityType, and PartitionKeyIAuditableEntity: Adds creation and modification tracking with timezone supportIDeletableEntity: Enables soft delete capabilitiesIRestorableEntity: Extends soft delete with restoration trackingIEtagEntity: Provides optimistic concurrency controlITimeToLiveEntity: Automatic entity expiration
Repository Interfaces
IReadOnlyRepository<TEntity>: Query, retrieval, counting, and pagination operationsIWriteOnlyRepository<TEntity>: Create, update, delete, and restore operationsIBatchRepository<TEntity>: Batch operations for multiple entitiesIRepository<TEntity>: Combined interface extending all repository types
Entity Base Classes
BaseEntity
public abstract record BaseEntity : IEntity
{
public string Id { get; set; } = Guid.NewGuid().ToString();
public string EntityType { get; init; }
string IEntity.PartitionKey => GetPartitionKeyValue();
}
Entity (Full-Featured)
public abstract record Entity : BaseEntity, IEtagEntity, ITimeToLiveEntity, IAuditableEntity
{
public string Etag { get; init; }
public TimeSpan? TimeToLive { get; set; }
public DateTimeOffset? CreatedOn { get; set; }
public string? CreatedBy { get; set; }
public string? CreatedInTimeZone { get; set; }
public DateTimeOffset ModifiedOn { get; }
public string ModifiedBy { get; set; }
public string? ModifiedInTimeZone { get; set; }
}
SoftDeleteEntity
public abstract record SoftDeleteEntity : Entity, IRestorableEntity
{
public string DeletedBy { get; set; }
public DateTimeOffset? DeletedOn { get; set; }
public string? DeletedInTimeZone { get; set; }
public bool IsDeleted { get; set; }
public int RestoreCount { get; set; }
}
Key Features
1. Comprehensive Querying
// Expression-based queries
var results = await repository.QueryAsync(x => x.Name.Contains("test"));
// Cursor-based pagination (recommended for large datasets)
CursorResult<MyEntity> cursorPage = await repository.PageCursorAsync(
predicate: x => x.IsActive,
pageSize: 20,
cursor: null);
// Offset-based pagination (for traditional paged UIs)
PagedResult<MyEntity> pagedResult = await repository.PageAsync(
predicate: null,
pageNumber: 1,
pageSize: 10);
// Slice for simple "load more" scenarios
SliceResult<MyEntity> slice = await repository.SliceAsync(
predicate: x => x.IsActive,
count: 10);
// Async enumeration for large datasets
await foreach (var entity in repository.SequenceQueryAsync(x => x.Category == "Important"))
{
// Process entity
}
2. Partial Updates with Patch Operations
// Expression-based patch operations
await repository.UpdatePartialAsync(entityId, builder => builder
.Set(x => x.Name, "New Name")
.Increment(x => x.ViewCount, 1)
.Add(x => x.Tags, "new-tag")
.Remove(x => x.ObsoleteField));
// Path-based operations for interface properties
await repository.UpdatePartialAsync(entityId, builder => builder
.SetByPath("status", "Active")
.IncrementByPath("score", 10));
3. Soft Delete and Restore
// Soft delete
await repository.DeleteAsync(entityId, softDelete: true);
// Restore with tracking
var (wasRestored, entity) = await repository.RestoreAsync(entityId);
// Batch restore
var results = await repository.RestoreAsBatchAsync(entities);
4. Batch Operations
// All entities must share the same partition
await repository.CreateAsBatchAsync(entities);
await repository.UpdateAsBatchAsync(entities);
await repository.DeleteAsBatchAsync(entities, softDelete: true);
5. Advanced Query Options
// Include soft-deleted entities
var allEntities = await repository.GetAllAsync(includeDeleted: true);
// Check existence
var exists = await repository.ExistsAsync(x => x.Email == "user@example.com");
// Count with filters
var count = await repository.CountAsync(x => x.IsActive && !x.IsDeleted);
Attributes for Persistence Configuration
Container Specification
[Container("my-container")]
public record MyEntity : Entity;
Partition Key Configuration
[PartitionKeyPath("/tenantId")]
public record TenantEntity : Entity {
public string TenantId { get; set; }
protected override string GetPartitionKeyValue() => this.TenantId;
}
Unique Key Constraints
public record UserEntity : Entity {
[UniqueKey("email-key", "/email")]
public string Email { get; set; }
[UniqueKey("username-key", "/username")]
public string Username { get; set; }
}
Indexing Policy Configuration
Declaratively define indexing policies directly on entity classes. When the persistence provider supports auto-creation, these attributes drive the container's indexing policy.
Indexing Mode and Behavior
[IndexingPolicy(IndexingMode.Consistent, Automatic = true)]
public record MyEntity : Entity;
Included and Excluded Paths
[IndexingPolicy(IndexingMode.Consistent)]
[ExcludedPath("/content/*")]
[ExcludedPath("/*")]
public record MyEntity : Entity {
[IncludedPath]
public string Status { get; set; }
[IncludedPath("/customPath/?")]
public string CustomField { get; set; }
}
When no explicit path is provided, [IncludedPath] auto-derives the path from the [JsonPropertyName] attribute or camelCase property name as /{name}/?.
Composite Indexes
[IndexingPolicy(IndexingMode.Consistent)]
[ExcludedPath("/*")]
public record TaskItem : Entity {
[IncludedPath]
[CompositeIndex("type-client-date", CompositePathSortOrder.Ascending, position: 0)]
public string Type { get; set; }
[IncludedPath]
[CompositeIndex("type-client-date", CompositePathSortOrder.Ascending, position: 1)]
public string ClientId { get; set; }
[IncludedPath]
[CompositeIndex("type-client-date", CompositePathSortOrder.Descending, position: 2)]
public DateTimeOffset CreatedAt { get; set; }
}
Properties are grouped into composite indexes by GroupName and ordered by Position. A property can participate in multiple composite index groups by applying the attribute multiple times.
Spatial Indexes
[IndexingPolicy(IndexingMode.Consistent)]
public record LocationEntity : Entity {
[SpatialIndex(SpatialType.Point)]
public Location Coordinates { get; set; }
}
Available Enums
IndexingMode:Consistent,Lazy,NoneCompositePathSortOrder:Ascending,DescendingSpatialType:Point,LineString,Polygon,MultiPolygon
Pagination Support
The library provides three pagination approaches via types from Cirreum.Result:
Cursor-Based Paging (Recommended)
- Stable results when data is being inserted or deleted
- Consistent performance regardless of how deep into the result set
- Ideal for large datasets, real-time data, and infinite scroll interfaces
- Returns
CursorResult<T>withNextCursor,HasNextPage, and optionalTotalCount
Offset-Based Paging
- Traditional page number-based paging with arbitrary page jumps
- Includes total counts for displaying "Page X of Y"
- Performance degrades on deep pages; results can shift between requests
- Returns
PagedResult<T>withPageNumber,PageSize,TotalCount, andTotalPages
Slice
- Simple "load more" pattern without full pagination metadata
- Fetches N+1 items to check if more exist
- Ideal for "Show More" buttons or batch processing
- Returns
SliceResult<T>withItemsandHasMore
Timezone Support
All audit fields support IANA timezone identifiers:
entity.CreatedInTimeZone = "America/Phoenix";
entity.ModifiedInTimeZone = "Europe/London";
entity.DeletedInTimeZone = "Asia/Tokyo";
Thread Safety and Concurrency
- ETag-based optimistic concurrency control
- Concurrency tokens for partial updates
- Thread-safe read operations
- Batch operations require entities in same partition
Best Practices
- Inherit from appropriate base classes: Use
Entityfor full features,BaseEntityfor minimal requirements - Implement partition strategy: Override
GetPartitionKeyValue()for custom partitioning - Use cursor paging: Prefer
PageCursorAsyncoverPageAsyncfor large datasets and infinite scroll - Use slice for simple scenarios: Use
SliceAsyncwhen you just need "load more" without page numbers - Batch same-partition entities: Ensure batch operations only include entities from the same partition
- Handle soft deletes: Use
includeDeletedparameter appropriately in queries - Leverage partial updates: Use patch operations for efficient field-level updates
Dependencies
This library has minimal dependencies:
- Cirreum.Result for pagination result types (
CursorResult<T>,PagedResult<T>,SliceResult<T>) - System.Text.Json for serialization attributes
- System.Linq.Expressions for query building
Integration
This abstraction layer is designed to be implemented by concrete persistence providers such as:
- Azure Cosmos DB
- MongoDB
- Entity Framework Core
- Any document or relational database
The clean separation ensures your domain logic remains persistence-agnostic while providing rich functionality through the unified interface.
Contributing
This package is part of the Cirreum ecosystem. Follow the established patterns when contributing new features or provider implementations.
Cirreum Foundation Framework
Layered simplicity for modern .NET
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 is compatible. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Cirreum.Result (>= 2.0.0)
-
net8.0
- Cirreum.Result (>= 2.0.0)
-
net9.0
- Cirreum.Result (>= 2.0.0)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Cirreum.Persistence.NoSql:
| Package | Downloads |
|---|---|
|
Cirreum.Persistence.Azure
Persistence Library using Azure Cosmos DB for NoSQL. |
GitHub repositories
This package is not used by any popular GitHub repositories.