Zonit.Extensions.Databases.SqlServer 0.1.8

There is a newer version of this package available.
See the version list below for details.
dotnet add package Zonit.Extensions.Databases.SqlServer --version 0.1.8
                    
NuGet\Install-Package Zonit.Extensions.Databases.SqlServer -Version 0.1.8
                    
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.SqlServer" Version="0.1.8" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Zonit.Extensions.Databases.SqlServer" Version="0.1.8" />
                    
Directory.Packages.props
<PackageReference Include="Zonit.Extensions.Databases.SqlServer" />
                    
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.SqlServer --version 0.1.8
                    
#r "nuget: Zonit.Extensions.Databases.SqlServer, 0.1.8"
                    
#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.
#addin nuget:?package=Zonit.Extensions.Databases.SqlServer&version=0.1.8
                    
Install Zonit.Extensions.Databases.SqlServer as a Cake Addin
#tool nuget:?package=Zonit.Extensions.Databases.SqlServer&version=0.1.8
                    
Install Zonit.Extensions.Databases.SqlServer 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

  • Speed up repository work � focus on your logic, not on database �plumbing�.
  • Simple abstractions for common CRUD operations.
  • Full support for DTO models.
  • Built-in support for query building (Where, Include, Select, paging, ordering and more).
  • Plug-and-play: Easily extend repositories with custom methods or external data without touching the extension itself.

💡 New! Extension Methods for External Data

Now you can easily include properties and data from outside your database, for example, by pulling from an external API or service.
This is useful when your model should have extra fields, computed properties, or needs to include data fetched live (not loaded from your DB).

How it works:

  1. Create an Extension Class implementing IDatabaseExtension<TModel>
    • In this class, implement business logic for fetching or computing the desired data.
using Zonit.Extensions.Databases.Examples.Entities;

namespace Zonit.Extensions.Databases.Examples.Extensions;

public class UserExtension : IDatabaseExtension<UserModel>
{
    public async Task<UserModel> InicjalizeAsync(Guid userId, CancellationToken cancellationToken = default)
    {
        // EXAMPLE: Here we would call a REST API or any other source.
        var model = new UserModel { 
            Id = userId,
            Name = "UserName",
        };
        return await Task.FromResult(model);
    }
}
  1. Reference the extension using .Extension() in your repository query chain.
var user = await _userRepository.Extension(x => x.UserExtension).GetAsync(userId);

The .Extension(x => x.UserExtension) call tells the repository to supply or load the UserExtension property for your entity.
This can be virtual, NotMapped, or simply a property populated on demand.

Use Case:
Suppose your Blog Entity has a UserModel? User property, but you want to always fetch the latest user data from an API instead of the DB.
Simply create an extension and reference it. The fetching, mapping, and attach process is handled by the extension system for you.

📖 Example Usage

Entity Model

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

    [NotMapped]
    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;
}

DTO Example

internal class BlogDto(Blog x)
{
    public string Id { get; set; } = $"Id: {x.Id}";
    public string Title { get; set; } = $"Title: {x.Title}";
    public string Content { get; set; } = $"Content: {x.Content}";
    public string Created { get; set; } = $"Created: {x.Created:G}";
}

public class UserModel
{
    public Guid Id { get; set; }
    public string Name { get; set; } = string.Empty;
}

Repository Implementation

public interface IBlogRepository : IDatabaseRepository<Blog, Guid> { }

internal class BlogRepository(DatabaseContext _context)
    : DatabaseRepository<Blog, Guid>(_context), IBlogRepository { }

public interface IBlogsRepository : IDatabasesRepository<Blog> { }

internal class BlogsRepository(IDbContextFactory<DatabaseContext> _context)
    : DatabasesRepository<Blog, DatabaseContext>(_context), IBlogsRepository { }

Service Registration / Dependency Injection

builder.Services.AddDbSqlServer<DatabaseContext>();

builder.Services.AddTransient<IBlogRepository, BlogRepository>();
builder.Services.AddTransient<IBlogsRepository, BlogsRepository>();

⚙️ CRUD Operations

Create

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

Read (Single or DTO)

var blogSingle = await _blogRepository.GetAsync(x => x.Title == "Hello World");
var blogSingleDto = await _blogRepository.GetAsync<BlogDto>(x => x.Title == "Hello World");

Read First

var blogFirst = await _blogRepository.GetFirstAsync(x => x.Title == "Hello World");
var blogFirstDto = await _blogRepository.GetFirstAsync<BlogDto>(x => x.Title == "Hello World");

Or:

var repository = _blogsRepository;
var blogs = await repository.OrderBy(x => x.Created).GetFirstAsync();
var blogsDto = await repository.OrderBy(x => x.Created).GetFirstAsync<BlogDto>();

Update

var blog = await _blogRepository.GetFirstAsync(x => x.Title == "Hello World");
blog.Title = "New Title";
var update = await _blogRepository.UpdateAsync(blog);

Delete

var delete = await _blogRepository.DeleteAsync(blog.Id);

Or

var blog = await _blogRepository.GetFirstAsync(x => x.Title == "Hello World");
var delete = await _blogRepository.DeleteAsync(blog);

Read All

var repository = _blogsRepository;
var blogs = await repository.GetAsync();
var blogsDto = await repository.GetAsync<BlogDto>();

📃 Repository APIs

IDatabaseRepository<TEntity, TType>

Task<TEntity> AddAsync(TEntity entity, CancellationToken cancellationToken = default);
Task<TDto> AddAsync<TDto>(TEntity entity, CancellationToken cancellationToken = default);

Task<TEntity?> GetAsync(TType id, CancellationToken cancellationToken = default);
Task<TDto?> GetAsync<TDto>(TType id, CancellationToken cancellationToken = default);

Task<TEntity?> GetAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);
Task<TDto?> GetAsync<TDto>(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);

Task<TEntity?> GetFirstAsync(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);
Task<TDto?> GetFirstAsync<TDto>(Expression<Func<TEntity, bool>> predicate, CancellationToken cancellationToken = default);

Task<bool> UpdateAsync(TEntity entity, CancellationToken cancellationToken = default);

Task<bool> DeleteAsync(TType entity, CancellationToken cancellationToken = default);
Task<bool> DeleteAsync(TEntity entity, CancellationToken cancellationToken = default);

IDatabaseReadRepository<TEntity> Extension(Expression<Func<TEntity, object?>> extension);

IDatabasesRepository<TEntity>

IDatabasesRepository<TEntity> Query();
IDatabasesRepository<TEntity> Extension(Expression<Func<TEntity, object?>> extension);
IDatabasesRepository<TEntity> Skip(int skip);
IDatabasesRepository<TEntity> Take(int take);
IDatabasesRepository<TEntity> Include(Expression<Func<TEntity, object>> includeExpression);
IDatabasesRepository<TEntity> Where(Expression<Func<TEntity, bool>> predicate);
IDatabasesRepository<TEntity> OrderBy(Expression<Func<TEntity, object>> keySelector);
IDatabasesRepository<TEntity> OrderByDescending(Expression<Func<TEntity, object>> keySelector);
IDatabasesRepository<TEntity> Select(Expression<Func<TEntity, TEntity>> selector);

Task<IReadOnlyCollection<TEntity>?> GetAsync(CancellationToken cancellationToken = default);
Task<IReadOnlyCollection<TDto>?> GetAsync<TDto>(CancellationToken cancellationToken = default);

Task<TEntity?> GetFirstAsync(CancellationToken cancellationToken = default);
Task<TDto?> GetFirstAsync<TDto>(CancellationToken cancellationToken = default);

Task<int?> UpdateRangeAsync(Action<TEntity> updateAction, CancellationToken cancellationToken = default);
Task<int> GetCountAsync(CancellationToken cancellationToken = default);

🌟 Why use this extension?

  • Build repository pattern code faster and cleaner.
  • Decouple your database logic from your app logic.
  • At any time, extend your repositories with custom business logic or fetch data from external APIs with zero changes to the extension library.
  • Full control: you can always create custom methods in your repository when needed.

ℹ️ For more examples

See the Examples 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. 
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
1.0.3 50 4/25/2025
1.0.2 112 4/23/2025
1.0.1 109 4/22/2025
1.0.0 67 4/19/2025
0.1.14 70 4/19/2025
0.1.13 75 4/19/2025
0.1.12 184 4/18/2025
0.1.11 170 4/17/2025
0.1.10 177 4/17/2025
0.1.9 176 4/17/2025
0.1.8 168 4/17/2025
0.1.7 167 4/17/2025
0.1.6 185 4/16/2025
0.1.5 93 1/29/2025
0.1.4 128 6/13/2024
0.1.3 110 6/5/2024
0.1.2 110 6/4/2024
0.1.1 106 6/4/2024
0.1.0 114 6/3/2024
0.0.13 105 5/1/2024
0.0.12 111 4/28/2024
0.0.11 130 4/24/2024
0.0.10 117 4/22/2024
0.0.9 114 4/21/2024
0.0.8 133 4/21/2024
0.0.7 122 4/18/2024
0.0.6 116 4/18/2024