Kanject.Core.SqlDatabase.Abstractions 1.3.1

Prefix Reserved
dotnet add package Kanject.Core.SqlDatabase.Abstractions --version 1.3.1
                    
NuGet\Install-Package Kanject.Core.SqlDatabase.Abstractions -Version 1.3.1
                    
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.SqlDatabase.Abstractions" Version="1.3.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Kanject.Core.SqlDatabase.Abstractions" Version="1.3.1" />
                    
Directory.Packages.props
<PackageReference Include="Kanject.Core.SqlDatabase.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.SqlDatabase.Abstractions --version 1.3.1
                    
#r "nuget: Kanject.Core.SqlDatabase.Abstractions, 1.3.1"
                    
#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.SqlDatabase.Abstractions@1.3.1
                    
#: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.SqlDatabase.Abstractions&version=1.3.1
                    
Install as a Cake Addin
#tool nuget:?package=Kanject.Core.SqlDatabase.Abstractions&version=1.3.1
                    
Install as a Cake Tool

Kanject.Core.SqlDatabase.Abstractions

Provider-neutral contracts for Kanject's relational data layer: ISqlEntity, ISqlRepository<TEntity>, ISqlUnitOfWork, ISqlDbContext, the SqlQuerySpec query model, and the table descriptors a provider's source generator emits. Application services depend on these interfaces; the Amazon Aurora DSQL provider implements them.

The contract is designed for Native AOT and deliberately has no EF Core, no LINQ provider and no runtime model discovery. A query is a plain object of column names, operators and values — no expression trees — and table shapes arrive as compile-time-generated descriptors instead of being reflected from your classes.

Installation

dotnet add package Kanject.Core.SqlDatabase.Abstractions

Targets .NET 8, .NET 9 and .NET 10. The package has no dependencies and is Native AOT / trimming compatible.

It contains no database driver and no in-memory implementation — pair it with a provider (see Related packages; providers are commercially licensed).

Quick start

ISqlEntity is a marker with no members; the provider's attributes declare the primary key.

using Kanject.Core.SqlDatabase.Abstractions.Interfaces;

public sealed class Customer : ISqlEntity
{
    public Guid CustomerId { get; init; }
    public string Email { get; set; } = string.Empty;
    public string Status { get; set; } = "active";
    public DateTime CreatedAt { get; set; }
}

Code application services against ISqlRepository<TEntity>:

using Kanject.Core.SqlDatabase.Abstractions.Enums;
using Kanject.Core.SqlDatabase.Abstractions.Interfaces;
using Kanject.Core.SqlDatabase.Abstractions.Models;

public sealed class CustomerService(ISqlRepository<Customer> customers)
{
    public Task<Customer?> FindByEmailAsync(string email)
    {
        var spec = new SqlQuerySpec();
        spec.Filters.Add(new SqlFilter("email", SqlOperator.Equal, email));
        return customers.GetSingleAsync(spec);
    }

    public Task<IList<Customer>> ActivePageAsync(int pageIndex, int pageSize)
    {
        var spec = new SqlQuerySpec { ResultLimit = pageSize, ResultOffset = pageIndex * pageSize };
        spec.Filters.Add(new SqlFilter("status", SqlOperator.Equal, "active"));
        spec.OrderBy.Add(new SqlOrderBy("created_at", SqlOrderDirection.Descending));
        return customers.GetAllAsync(spec);
    }

    public Task<long> CountActiveAsync()
    {
        var spec = new SqlQuerySpec();
        spec.Filters.Add(new SqlFilter("status", SqlOperator.Equal, "active"));
        return customers.CountAsync(spec);
    }

    public Task SaveAsync(Customer customer) => customers.AddOrUpdateAsync(customer);
}

Column names in a spec are SQL column names, not C# property names. The DSQL provider maps properties to snake_case by default (CreatedAt → created_at) unless a [Column] attribute overrides it.

With the DSQL provider, the entity implements IDsqlEntity (which extends ISqlEntity) and marks its key with [PrimaryKey]. The provider's AddDbContext<TContext>() registers the unit of work against ISqlUnitOfWork, and AddDsqlRepository<TRepository, TEntity>() registers each generated repository against ISqlRepository<TEntity>, so the service above resolves unchanged.

Repository operations

Member SQL shape
GetSingleAsync(string id) Fetch by primary key (string form; composite keys use the provider's key composition)
GetSingleAsync(SqlQuerySpec) / GetAllAsync(SqlQuerySpec?) SELECT … WHERE … ORDER BY … LIMIT/OFFSET
AnyAsync(SqlQuerySpec?) / CountAsync(SqlQuerySpec?) Existence check / COUNT(*) (returns long)
InsertAsync(entity) / InsertRangeAsync INSERT
InsertAsync(entity, SqlQuerySpec) INSERT … ON CONFLICT DO NOTHING, conflict target from the spec's key predicates
AddOrUpdateAsync / AddOrUpdateRangeAsync INSERT … ON CONFLICT (pk) DO UPDATE
UpdateAsync / UpdateRangeAsync UPDATE by primary key
RemoveAsync / RemoveRangeAsync DELETE by primary key
SqlQueryAsync / SqlQueryAsync<TData> / ExecuteQueryAsync Raw-SQL escape hatches

Every *RangeAsync method also has a CancellationToken overload whose default implementation forwards to the token-less one.

The raw SqlQueryAsync<TData> is only AOT-safe when the projection type has a generator-emitted mapper; otherwise it falls back to driver-default mapping.

Building query specs

SqlQuerySpec holds KeyPredicates, Filters, OrderBy, ExistsPredicates, ResultLimit and ResultOffset. You can fill it directly (as above) or through SqlQuerySpecOption<TEntity>, whose Config property is the spec:

using Kanject.Core.SqlDatabase.Abstractions.Extensions;

var option = new SqlQuerySpecOption<Customer>().Limit(20).Offset(40);
option.Config.Filters.Add(new SqlFilter("email", SqlOperator.ILike, "%@example.com"));

IList<Customer> page = await customers.GetAllAsync(option.Config);

Providers with a source generator emit typed per-column extensions on SqlQuerySpecOption<TEntity> — Where{Column}, OrderBy{Column} and friends in the DSQL provider. DbFunc builds the (SqlOperator, value) tuples those extensions accept:

using Kanject.Core.SqlDatabase.Abstractions.Helpers;

// WhereCreatedAt / WhereStatus are generated for the entity by the DSQL annotations package.
var since = DateTime.UtcNow.AddDays(-30);
option.WhereCreatedAt(DbFunc.GreaterThanOrEqual(since))
      .WhereStatus(DbFunc.In("active", "trial"));

DbFunc covers Equal, NotEqual, LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual, Like, ILike, In, NotIn and Between. SqlOperator additionally has IsNull and IsNotNull.

Units of work

ISqlUnitOfWork resolves repositories and scopes a transaction:

// Account is an ISqlEntity like Customer above.
public sealed class TransferService(ISqlUnitOfWork unitOfWork)
{
    public async Task MoveAsync(Account from, Account to, CancellationToken cancellationToken)
    {
        var accounts = unitOfWork.Repository<Account>();

        unitOfWork.BeginTransaction();
        await accounts.UpdateAsync(from);
        await accounts.UpdateAsync(to);
        await unitOfWork.CommitAsync(cancellationToken);
    }
}

The contract leaves it to the implementation whether BeginTransaction/CommitAsync open a real database transaction. The DSQL provider does: it issues BEGIN on a dedicated connection that every repository call in the same scope enlists in, COMMIT on CommitAsync, and rolls back if the unit of work is disposed without committing. It registers the unit of work as scoped, and its own unit-of-work interface adds BeginTransactionAsync and RollbackAsync.

Schema descriptors

ISqlDbContext exposes the default Schema and GetTableDescriptors(). A provider's source generator emits one SqlTableDescriptor per repository-bound entity — Schema, Table, PrimaryKey (SqlPrimaryKey), Columns (SqlColumnDescriptor: name, database type, nullability) and Indexes (SqlIndexDescriptor). A provider's schema applier creates missing schemas, tables and indexes from that list (the DSQL provider does so at startup when its schema check is enabled). Nothing inspects your entity classes at runtime.

Public surface at a glance

Type Purpose
ISqlEntity Marker for persistable entities
ISqlRepository, ISqlRepository<TEntity> Untyped (raw SQL, context binding) and typed CRUD contracts
ISqlUnitOfWork Repository resolution and transaction scope; IDisposable and IAsyncDisposable
ISqlDbContext Default schema plus compile-time table descriptors
SqlQuerySpec, SqlKeyPredicate, SqlFilter, SqlOrderBy, SqlExistsPredicate Structured WHERE / ORDER BY / EXISTS / LIMIT / OFFSET
SqlQuerySpecOption<TEntity>, SqlQuerySpecExtensions (Limit, Offset), DbFunc Fluent spec building
SqlTableDescriptor, SqlPrimaryKey, SqlColumnDescriptor, SqlIndexDescriptor Generated schema description
BatchWriteConfig Range-write chunking defaults: 1,000 rows or 4 MiB per chunk; COPY FROM STDIN BINARY from 10,000 rows
SqlOperator, SqlOrderDirection, SqlEnvironment (Remote, Local) Enumerations
SqlUpdateOption<TEntity>, SqlUpdateExpression, SqlConditionalExpression, SqlUpdateOperator Update-side shapes; no ISqlRepository<TEntity> method takes them yet
Package Role Availability
Kanject.Core.NoSqlDatabase.Abstractions The NoSQL counterpart of this contract nuget.org
Kanject.Core.SqlDatabase.Provider.Dsql Amazon Aurora DSQL runtime and DI registration Commercial license (not on nuget.org)
Kanject.Core.SqlDatabase.Provider.Dsql.Abstractions DSQL contracts (IDsqlEntity, IDsqlRepository<TEntity>, IDsqlUnitOfWork) and configuration Commercial license (not on nuget.org)
Kanject.Core.SqlDatabase.Provider.Dsql.Annotations Source generator and analyzers that emit the AOT-safe repositories Commercial license (not on nuget.org)
Kanject.Core.SqlDatabase.Provider.Dsql.Annotations.Attributes [Table], [PrimaryKey], [Column], [Repository] and related attributes 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.
  • net10.0

    • No dependencies.
  • net8.0

    • No dependencies.
  • net9.0

    • No dependencies.

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
1.3.1 123 9/27/2026
1.3.0 86 9/27/2026
1.2.7 86 9/26/2026
1.2.6 119 9/7/2026
1.2.5 99 8/27/2026
1.2.4 100 8/22/2026
1.2.3 113 8/10/2026
1.2.2 107 8/9/2026
1.2.1 105 8/5/2026
1.2.0 101 8/5/2026
1.1.0 117 8/3/2026
1.0.5 116 7/30/2026
1.0.4 120 7/18/2026
1.0.3 127 7/13/2026
1.0.2 118 7/11/2026
1.0.1 116 7/11/2026
1.0.0 117 7/9/2026