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
<PackageReference Include="Zonit.Extensions.Databases.Abstractions" Version="1.1.1" />
<PackageVersion Include="Zonit.Extensions.Databases.Abstractions" Version="1.1.1" />
<PackageReference Include="Zonit.Extensions.Databases.Abstractions" />
paket add Zonit.Extensions.Databases.Abstractions --version 1.1.1
#r "nuget: Zonit.Extensions.Databases.Abstractions, 1.1.1"
#:package Zonit.Extensions.Databases.Abstractions@1.1.1
#addin nuget:?package=Zonit.Extensions.Databases.Abstractions&version=1.1.1
#tool nuget:?package=Zonit.Extensions.Databases.Abstractions&version=1.1.1
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
SQL Server Implementation
Install-Package Zonit.Extensions.Databases.SqlServer
đ Features
- Simplified Repository - Single dependency constructor with
RepositoryContext<TContext> - Fluent Query API -
Where,Include,ThenInclude,OrderBy,Skip,Takeand more - Direct API on Repository - No
AsQuery()needed, justrepo.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()andContextFactoryfor 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 | 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
- 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 |