Zonit.Extensions.Databases.Abstractions 1.1.1

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

Zonit.Extensions.Databases

Zonit.Extensions.Databases is a flexible library for building repositories and handling CRUD operations on databases.
It provides abstractions and interfaces, making it easy to manage database access and to extend your repositories with custom logic, REST API data, or other external sources.
You can use your own repositories and expand them anytime with additional functions, while still keeping your codebase clean and modular.

đŸ“Ļ NuGet Packages

Abstraction

Install-Package Zonit.Extensions.Databases.Abstractions 

NuGet Version NuGet

SQL Server Implementation

Install-Package Zonit.Extensions.Databases.SqlServer

NuGet Version NuGet

🚀 Features

  • Simplified Repository - Single dependency constructor with RepositoryContext<TContext>
  • Fluent Query API - Where, Include, ThenInclude, OrderBy, Skip, Take and more
  • Direct API on Repository - No AsQuery() needed, just repo.Where(...).GetListAsync()
  • Table Naming Convention - SetPrefix("Schema", "Prefix") for automatic table configuration
  • Extension Properties Convention - Automatic in DatabaseContextBase (no manual call needed)
  • Protected Context Access - CreateContextAsync() and ContextFactory for custom queries
  • Smart Delete - Single DeleteAsync() method with automatic soft delete detection
  • Value Objects Support - Automatic EF Core converters for Title, Price, Culture, etc.

🌟 Quick Start

1. Create Repository (Simplified!)

// Single RepositoryContext<TContext> contains everything you need
internal class BlogRepository(RepositoryContext<DatabaseContext> context)
    : SqlServerRepository<Blog, DatabaseContext>(context), IBlogRepository
{
    // Custom method with direct database access
    public async Task<Blog?> GetRecentAsync()
    {
        // Protected method for direct DbContext access
        await using var context = await CreateContextAsync();
        
        return await context.Blogs
            .Where(b => b.Created > DateTime.UtcNow.AddDays(-7))
            .FirstOrDefaultAsync();
    }
}

2. Entity Model (No [NotMapped] needed!)

public class Blog
{
    public Guid Id { get; set; }

    // No [NotMapped] attribute needed - use IgnoreExtensionProperties() in OnModelCreating
    public UserModel? User { get; set; }
    public Guid? UserId { get; set; }

    public string Title { get; set; } = string.Empty;
    public string Content { get; set; } = string.Empty;
    public DateTime Created { get; private set; } = DateTime.UtcNow;
}

3. DbContext Configuration (Simplified!)

internal class DatabaseContext(DbContextOptions<DatabaseContext> options) 
    : DatabaseContextBase<DatabaseContext>(options)
{
    public DbSet<Blog> Blogs { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Simplified table naming - replaces manual foreach loop
        // Creates tables: [Zonit].[Examples.Blog], [Zonit].[Examples.User]
        modelBuilder.SetPrefix("Zonit", "Examples");

        // Call base to enable:
        // - Value Objects converters
        // - Auto-ignore extension properties (configurable via AutoIgnoreExtensionProperties)
        base.OnModelCreating(modelBuilder);
    }
    
    // Optional: Disable auto-ignoring extension properties
    // protected override bool AutoIgnoreExtensionProperties => false;
}

📖 Fluent Query API

All query methods are available directly on the repository - no AsQuery() call needed!

Filter with Where

var blogs = await repo.Where(x => x.Title.Contains("C#")).GetListAsync();
var firstBlog = await repo.Where(x => x.Title == "Hello").GetFirstAsync();

Eager Loading with Include / ThenInclude

// Single navigation property
var blog = await repo
    .Include(x => x.User)
    .Where(x => x.Id == blogId)
    .GetAsync();

// ThenInclude for nested navigation
var blog = await repo
    .Include(x => x.User)
        .ThenInclude(u => u.Organization)
    .Where(x => x.Id == blogId)
    .GetAsync();

// Collection includes (same method, different signature)
var blog = await repo
    .Include(x => x.Comments)
        .ThenInclude(c => c.Author)
    .GetAsync();

Ordering

var blogs = await repo
    .OrderByDescending(x => x.Created)
    .ThenBy(x => x.Title)
    .GetListAsync();

Pagination

var page = await repo
    .OrderBy(x => x.Created)
    .Skip(20)
    .Take(10)
    .GetListAsync();

Count and Exists

var count = await repo.CountAsync();
var exists = await repo.Where(x => x.Title == "Test").AnyAsync();

âš™ī¸ CRUD Operations

Create

var blog = await repo.AddAsync(new Blog
{
    Title = "Hello World",
    Content = "Example content"
});

Read

// By ID
var blog = await repo.GetByIdAsync(blogId);

// With DTO mapping
var blogDto = await repo.GetByIdAsync<BlogDto>(blogId);

// First with filter
var blog = await repo.Where(x => x.Title == "Hello").GetFirstAsync();

// All
var blogs = await repo.GetListAsync();

Update

// By ID with action
await repo.UpdateAsync(blogId, entity => entity.Title = "New Title");

// Or pass entity
blog.Title = "New Title";
await repo.UpdateAsync(blog);

Delete

// Default: soft delete if entity implements ISoftDeletable, otherwise hard delete
await repo.DeleteAsync(blogId);
// or
await repo.DeleteAsync(blog);

// Force hard delete (permanently remove even if ISoftDeletable)
await repo.DeleteAsync(blogId, forceDelete: true);

Soft Delete with ISoftDeletable

Implement ISoftDeletable interface for automatic soft delete behavior:

// Entity implements interface with optional custom logic
public class Blog : ISoftDeletable
{
    public Guid Id { get; set; }
    public string Title { get; set; }
    public string Status { get; set; } = "active";
    
    // Required by ISoftDeletable
    public DateTimeOffset? DeletedAt { get; set; }
    
    // Optional: Override to add custom logic when soft deleting
    public void OnSoftDelete()
    {
        Status = "deleted";
        // Add any additional cleanup logic here
    }
}

// Usage - automatically sets DeletedAt and calls OnSoftDelete()
await repo.DeleteAsync(blogId);

// Restore (clears DeletedAt)
await repo.RestoreAsync(blogId);

Delete behavior: | Entity Type | forceDelete: false (default) | forceDelete: true | |-------------|-------------------------------|---------------------| | Implements ISoftDeletable | Soft delete (sets DeletedAt, calls OnSoftDelete()) | Hard delete (removes from DB) | | Does NOT implement ISoftDeletable | Hard delete | Hard delete |

💡 Extension Properties

Load data from external sources (API, other services) into your entities:

1. Create Extension Handler

public class UserExtension : IDatabaseExtension<UserModel>
{
    public async Task<UserModel> InitializeAsync(Guid userId, CancellationToken ct = default)
    {
        // Fetch from external API, cache, or compute
        return new UserModel { Id = userId, Name = "Loaded from API" };
    }
}

2. Use in Query

var blog = await repo
    .Extension(x => x.User)  // Load User via extension
    .Where(x => x.Id == blogId)
    .GetAsync();

Console.WriteLine(blog.User?.Name); // "Loaded from API"

đŸ“Ļ Value Objects Support

Inherit from DatabaseContextBase<T> to automatically enable EF Core converters:

Value Object Database Type Max Length Use Case
Culture NVARCHAR(10) 10 Language codes (en-US, pl-PL)
UrlSlug NVARCHAR(200) 200 SEO-friendly URLs
Title NVARCHAR(60) 60 Page/content titles
Description NVARCHAR(160) 160 Meta descriptions
Content NVARCHAR(MAX) - Large text content
Url NVARCHAR(2048) 2048 URLs with validation
Price DECIMAL(19,8) - Product prices (non-negative)
Money DECIMAL(19,8) - Balances, transactions (can be negative)
Color NVARCHAR(100) 100 Colors in OKLCH format
Asset VARBINARY(MAX) - Files with metadata
public class Article
{
    public Guid Id { get; set; }
    public Title Title { get; set; }           // Auto-converted, max 60 chars
    public Description Description { get; set; } // Auto-converted, max 160 chars
    public Price Price { get; set; }            // Auto-converted, decimal(19,8)
}

🔧 Service Registration

// Register DbContext factory
builder.Services.AddDbSqlServer<DatabaseContext>(options => 
    options.UseSqlServer(connectionString));

// Register repository - IServiceProvider is optional now!
builder.Services.AddTransient<IBlogRepository, BlogRepository>();

â„šī¸ For more examples

See the Example project included in the repository.

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 (1)

Showing the top 1 NuGet packages that depend on Zonit.Extensions.Databases.Abstractions:

Package Downloads
Zonit.Extensions.Databases

Core database repository library for .NET with fluent query API, DTO mapping, and external data extensions. Install provider packages (SqlServer, PostgreSql, MySql) separately.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.1.1 32 1/24/2026
1.0.57 80 1/21/2026
1.0.56 99 1/16/2026
1.0.55 102 1/15/2026
1.0.54 99 1/12/2026
1.0.53 106 1/6/2026
1.0.52 106 1/4/2026
1.0.51 102 1/2/2026
1.0.50 420 11/18/2025
1.0.13 214 8/12/2025
1.0.12 333 6/12/2025
1.0.11 344 6/11/2025
1.0.10 331 6/11/2025
1.0.9 196 5/29/2025
1.0.8 193 5/28/2025
1.0.7 194 5/28/2025
1.0.6 127 5/24/2025
1.0.5 199 5/19/2025
1.0.4 216 5/7/2025
1.0.3 176 4/25/2025
1.0.2 225 4/23/2025
1.0.1 239 4/22/2025
1.0.0 169 4/19/2025
0.1.14 159 4/19/2025
0.1.13 168 4/19/2025
0.1.12 272 4/18/2025
0.1.11 260 4/17/2025
0.1.10 262 4/17/2025
0.1.9 263 4/17/2025
0.1.8 263 4/17/2025
0.1.7 262 4/17/2025
0.1.6 280 4/16/2025
0.1.5 182 1/29/2025
0.1.4 218 6/13/2024
0.1.3 185 6/5/2024
0.1.2 189 6/4/2024
0.1.1 199 6/4/2024
0.1.0 198 6/3/2024
0.0.13 203 5/1/2024
0.0.12 180 4/28/2024
0.0.11 216 4/24/2024
0.0.10 191 4/22/2024
0.0.9 205 4/21/2024
0.0.8 210 4/21/2024
0.0.7 224 4/18/2024
0.0.6 188 4/18/2024