Kanject.Core.NoSqlDatabase.Abstractions 4.7.0

Prefix Reserved
dotnet add package Kanject.Core.NoSqlDatabase.Abstractions --version 4.7.0
                    
NuGet\Install-Package Kanject.Core.NoSqlDatabase.Abstractions -Version 4.7.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Kanject.Core.NoSqlDatabase.Abstractions" Version="4.7.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Kanject.Core.NoSqlDatabase.Abstractions" Version="4.7.0" />
                    
Directory.Packages.props
<PackageReference Include="Kanject.Core.NoSqlDatabase.Abstractions" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Kanject.Core.NoSqlDatabase.Abstractions --version 4.7.0
                    
#r "nuget: Kanject.Core.NoSqlDatabase.Abstractions, 4.7.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Kanject.Core.NoSqlDatabase.Abstractions@4.7.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Kanject.Core.NoSqlDatabase.Abstractions&version=4.7.0
                    
Install as a Cake Addin
#tool nuget:?package=Kanject.Core.NoSqlDatabase.Abstractions&version=4.7.0
                    
Install as a Cake Tool

Kanject.Core.NoSqlDatabase.Abstractions

Provider-neutral contracts for the Kanject NoSQL data layer. The package defines the IEntity, IRepository<TEntity>, IUnitOfWork and IDbContext interfaces, a portable QueryOperator vocabulary with typed exceptions, shared request-filter models, and a few geospatial helpers. Domain and application code references this package. A provider package supplies the implementation for a specific store: Amazon DynamoDB, Amazon Keyspaces or ScyllaDB.

This package does not include a storage engine, and there is no in-memory NoSQL provider. To read or write data, you also need one of the Kanject provider packages listed under Related packages. Those packages require a commercial license.

Installation

dotnet add package Kanject.Core.NoSqlDatabase.Abstractions

Targets .NET 8, .NET 9 and .NET 10. Depends on Kanject.Core.

Quick start

Describe the entity against the shared contract. IEntity requires a string PartitionKey. IBaseEntityIdentifier<T> adds a typed Id.

using Kanject.Core.NoSqlDatabase.Abstractions.Interfaces;

public sealed class Order : IBaseEntityIdentifier<string>
{
    public string PartitionKey { get; set; } = string.Empty;
    public string Id { get; set; } = string.Empty;
    public string CustomerId { get; set; } = string.Empty;
    public decimal Total { get; set; }
}

Write application services against IRepository<TEntity> and IUnitOfWork:

using Kanject.Core.NoSqlDatabase.Abstractions.Interfaces;

public sealed class OrderService(IRepository<Order> orders, IUnitOfWork unitOfWork)
{
    public Task<Order?> FindAsync(string partitionKey) =>
        orders.GetSingleAsync(partitionKey);

    public Task SaveAsync(Order order) =>
        orders.AddOrUpdateAsync(order);

    public Task ImportAsync(IList<Order> batch, CancellationToken cancellationToken) =>
        orders.InsertRangeAsync(batch, cancellationToken);

    // Commit two writes as one unit.
    public async Task ReplaceAsync(Order current, Order replacement, CancellationToken cancellationToken)
    {
        orders.SetUnitOfWork(unitOfWork);   // enlist this repository's writes
        unitOfWork.BeginTransaction();
        await orders.RemoveAsync(current);
        await orders.InsertAsync(replacement);
        await unitOfWork.CommitAsync(cancellationToken);
    }
}

In the host, register a provider and make IRepository<Order> resolve to that provider's repository for Order. Kanject providers register IUnitOfWork for you. If your provider gives you a concrete repository class for each entity, forward the shared interface to it:

// OrderRepository is the repository class your provider gives you for Order,
// for example a source-generated [Repository] partial class.
builder.Services.AddScoped<IRepository<Order>>(sp => sp.GetRequiredService<OrderRepository>());
builder.Services.AddScoped<OrderService>();

With a real provider, the entity also implements that provider's entity interface and carries its mapping attributes. DynamoDB entities implement IDynamoDbEntity, which adds SortKey. Entities for the CQL providers implement ICqlEntity. Each provider's repository interface derives from IRepository<TEntity>, so services written against this package keep working.

Repositories

Member Purpose
GetSingleAsync(string id) Fetches one item, or returns null. The shipped providers treat id as the partition-key value.
InsertAsync / InsertRangeAsync Writes new items.
AddOrUpdateAsync / AddOrUpdateRangeAsync Inserts an item or replaces the existing one.
UpdateAsync / UpdateRangeAsync Updates existing items.
RemoveAsync / RemoveRangeAsync Deletes items.
SqlQueryAsync(string) / SqlQueryAsync<TData>(string) / ExecuteQueryAsync(string) Runs a raw statement in the store's own dialect: PartiQL on DynamoDB, CQL on Keyspaces and ScyllaDB.
SetUnitOfWork(...) / SetDbContext(...) Binds the repository to a unit of work or a database context.
DbContext / CurrentTableName Returns the bound context and the table the repository writes to.

Every *RangeAsync method has an overload that takes a CancellationToken. The default interface implementation forwards to the overload without a token, so whether the token is honoured depends on the provider.

On the CQL providers, SqlQueryAsync<TData> supports only the repository's own entity type. Use SqlQueryAsync(string) there instead.

Units of work and transactions

IUnitOfWork groups writes. Call BeginTransaction(), write through repositories bound with SetUnitOfWork(...), then call CommitAsync(...). IsTransactionEnabled is true while a transaction is open.

  • How a commit is carried out depends on the provider. The DynamoDB providers submit the buffered writes as one transactional write. CommitAsync(string clientRequestToken, ...) forwards the token as that request's idempotency token. The CQL providers (Keyspaces, ScyllaDB) flush the writes as a LOGGED BATCH. Their token overload requires a non-empty token but does not use it.
  • The unit of work is scoped. Kanject providers register IUnitOfWork with a scoped lifetime because it buffers per-unit transaction state. Do not capture it in a singleton.
  • Resolve repositories through DI or through the provider's own unit-of-work interface. The shipped providers do not implement the shared IUnitOfWork.Repository<TEntity>() overload, and calling it throws.
  • Read before you begin. Some providers reject reads such as GetSingleAsync while a transaction is open.

Query operators

Provider query builders accept QueryOperator values. The enum's integer values are fixed, so the wire format stays the same when a member is renamed.

Operators Portability
Equal, NotEqual, LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual, In, NotIn, Between, Contains, NotContains Comparison and filter operators. NotEqual, NotIn and NotContains work in filter expressions only.
BeginsWith, NotBeginsWith DynamoDB-native. CQL has no equivalent on arbitrary columns.
AttributeExist, AttributeNotExist DynamoDB only.
ContainsKey CQL only (map-key membership).
Set, Increment, Decrement, Remove, Add, Delete Update and delete actions.

SetIncrement, SetDecrement and RemoveAttribute are obsolete aliases for Increment, Decrement and Remove.

When a provider can't translate an operator, it throws QueryOperatorNotSupportedException. The exception's Operator and Provider properties are populated, so code that targets several stores can catch one typed exception:

using Kanject.Core.NoSqlDatabase.Abstractions.Exceptions;

try
{
    await RunPrefixSearchAsync(prefix);
}
catch (QueryOperatorNotSupportedException ex)
{
    logger.LogWarning("{Provider} cannot evaluate {Operator}; falling back.", ex.Provider, ex.Operator);
    await RunFullScanAsync(prefix);
}

Two more exceptions cover model problems:

  • InvalidModelBuilderException: an entity or model declaration fails a provider's pre-flight validation. It exposes EntityTypeName, TableName, MemberName and Provider.
  • CreateTableModelBuilderException: a provider fails to create a table from a valid model. It exposes TableName, Keyspace and Provider.

Request filters

These are small shapes for API query models. The interfaces all derive from the IFilter marker.

Type Members
IPaginationFilter / DataPaginationFilter PageToken, PageSize (JSON: pageToken, pageSize)
IDateRangeFilter / DateRangeFilter StartDate, EndDate (JSON: startDate, endDate)
IQueryFilter Query
IStatusFilter Status
IAuditFilter CreatedBy, ModifiedBy

"...".ParseFilter<TFilter>() in Kanject.Core.NoSqlDatabase.Abstractions.Filters.Extensions deserializes a JSON filter string with System.Text.Json. It returns null when the JSON is invalid. It uses reflection-based serialization.

Geospatial helpers

GeoPoint is an immutable WGS-84 latitude/longitude value. Its constructor throws ArgumentOutOfRangeException outside ±90° and ±180°. SphericalMath performs allocation-free great-circle calculations on a sphere with a mean radius of 6,371 km.

using Kanject.Core.NoSqlDatabase.Abstractions.Helpers.GeoHashing;
using Kanject.Core.NoSqlDatabase.Abstractions.Helpers.GeoHashing.Models;

var losAngeles = new GeoPoint(34.0522, -118.2437);
var lasVegas = new GeoPoint(36.1699, -115.1398);

double metres = SphericalMath.Distance(losAngeles, lasVegas);   // haversine, about 367,600 m
double bearing = SphericalMath.Bearing(losAngeles, lasVegas);   // about 49.3 degrees from true north
GeoPoint waypoint = SphericalMath.Destination(losAngeles, bearing, 100_000);

SphericalMath.ToRadians and ToDegrees are also public. GeoPoint.Lat and GeoPoint.Lon are obsolete aliases for Latitude and Longitude.

GeohashCodec encodes and decodes standard geohashes (the same strings other geohash libraries produce), and GeohashQueries builds on it for lookups:

using Kanject.Core.NoSqlDatabase.Abstractions.Helpers.GeoHashing.Enums;   // Direction

string hash = GeohashCodec.Encode(new GeoPoint(42.6, -5.6), precision: 5);           // "ezs42"
var (centre, latitudeError, longitudeError) = GeohashCodec.Decode(hash);             // cell centre ± half its size
string north = GeohashCodec.GetAdjacent(hash, Direction.North);                      // "ezs48"
IReadOnlySet<string> around = GeohashQueries.GetNeighbors(hash);                     // the 8 surrounding cells
ISet<string> covering = GeohashQueries.GetHashesInRadius(losAngeles, 1_000, precision: 7);

GetHashesInRadius returns every cell the circle touches, so a record stored under any point inside the circle is in one of them. Edge cells can reach past the circle, so filter the results by exact distance. A covering that would need more than 100,000 cells throws ArgumentOutOfRangeException instead of returning a partial set; use a lower precision for large radii. At the poles GetAdjacent keeps the row (there is no cell beyond the pole) and GetNeighbors leaves those cells out.

Geohashes computed by earlier versions of this package are not standard geohashes and do not round-trip. Recompute any stored geohash with the current Encode before querying against it.

Trimming and Native AOT

The package is built with the .NET trim and AOT analyzers enabled (IsAotCompatible). The data-access members of IRepository, IRepository<TEntity> and IUnitOfWork are annotated [RequiresUnreferencedCode] and [RequiresDynamicCode], and so is ParseFilter. The annotations exist because the providers' general query paths bind values dynamically or map entities by reflection. In a trimmed or Native AOT publish, calls to these members report IL2026 and IL3050 warnings at your call sites. Entities, filter models, enums, exceptions and the geospatial helpers carry no such annotations.

Public surface at a glance

Type Purpose
IEntity, IBaseEntityIdentifier<T> Entity contracts (PartitionKey, Id)
IRepository, IRepository<TEntity> Untyped and typed repository contracts
IUnitOfWork Groups writes into a transaction, then commits them
IDbContext Disposable marker for a provider's database context
QueryOperator, QueryCondition, OrderBy, QueryExecutionStatus Query vocabulary shared by providers
QueryOperatorNotSupportedException, InvalidModelBuilderException, CreateTableModelBuilderException Typed provider failures
IFilter and its derivatives, DataPaginationFilter, DateRangeFilter Request-filter shapes
GeoPoint, SphericalMath Coordinates and great-circle geometry
GeohashCodec, GeohashQueries, Direction Standard geohash encoding, neighbours and radius coverings
Package Role Availability
Kanject.Core Core runtime this package depends on nuget.org
Kanject.Core.SqlDatabase.Abstractions Contracts for the relational data layer nuget.org
Kanject.Core.NoSqlDatabase.Provider.DynamoDbV2 Amazon DynamoDB provider Commercial license (not on nuget.org)
Kanject.Core.NoSqlDatabase.Provider.DynamoDb Amazon DynamoDB provider (original runtime) Commercial license (not on nuget.org)
Kanject.Core.NoSqlDatabase.Provider.DynamoDb.Abstractions DynamoDB-specific contracts (IDynamoDbEntity, query configuration) Commercial license (not on nuget.org)
Kanject.Core.NoSqlDatabase.Provider.DynamoDb.Annotations DynamoDB source generators and analyzers Commercial license (not on nuget.org)
Kanject.Core.NoSqlDatabase.Provider.Keyspaces Amazon Keyspaces (Cassandra-compatible) provider Commercial license (not on nuget.org)
Kanject.Core.NoSqlDatabase.Provider.Keyspaces.Annotations Keyspaces source generators and analyzers Commercial license (not on nuget.org)
Kanject.Core.NoSqlDatabase.Provider.Scylla ScyllaDB provider Commercial license (not on nuget.org)
Kanject.Core.NoSqlDatabase.Provider.Cql Shared CQL runtime used by the Keyspaces and ScyllaDB providers Commercial license (not on nuget.org)
Kanject.Core.NoSqlDatabase.Provider.Cql.Abstractions CQL-specific contracts (ICqlEntity) Commercial license (not on nuget.org)

License

Licensed under the Kanject Code Libraries License Agreement (KCLLA); the full text ships in this package as LICENSE.md. Organizations whose trailing-twelve-month gross revenue and total funding raised are each below US$250,000 may use it at no cost under the Free Tier. At or above either threshold a commercial license is required — contact commercial@kanjectbusiness.com.

Product 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. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
4.7.0 81 10/5/2026
4.6.0 90 10/2/2026
4.5.1 115 9/27/2026
4.5.0 98 9/27/2026
4.4.7 93 9/26/2026
4.4.6 121 9/7/2026
4.4.5 104 8/27/2026
4.4.4 107 8/22/2026
4.4.3 125 8/10/2026
4.4.2 107 8/9/2026
4.4.1 130 8/5/2026
4.4.0 124 8/5/2026
4.3.0 121 8/3/2026
4.2.8 124 7/30/2026
4.2.7 131 7/18/2026
4.2.6 135 7/13/2026
4.2.5 127 7/11/2026
4.2.4 132 7/11/2026
4.2.3 128 7/9/2026
4.2.2 129 7/9/2026