RepoKit.Dapper 1.0.0

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

RepoKit 🎯

One attribute. Zero boilerplate. Full repository pattern.

A lightweight, production-ready .NET library that eliminates repository boilerplate through smart dependency injection. Add [AutoRepository] to your entity and instantly get a fully wired IRepository<T> with support for Entity Framework Core, Dapper, pagination, specifications, and Unit of Work.

NuGet version License: MIT .NET 8+ Build Status Quality Gate


✨ Features

  • 🎯 Zero Configuration - Single [AutoRepository] attribute to register repositories
  • 🔄 ORM Agnostic - Entity Framework Core, Dapper, or both in the same project
  • 📖 Specification Pattern - Type-safe, reusable query building
  • 📄 Built-in Pagination - PagedResult<T> with metadata
  • 🔗 Unit of Work - Atomic multi-repository operations with transactions
  • ⚡ High Performance - Minimal overhead; Dapper for raw SQL workloads
  • 📚 Full XML Docs - 100% documented with complete IntelliSense support
  • 🛡️ Null-Safe - Nullable reference types; comprehensive validation
  • 🎓 Clean Architecture Ready - SOLID principles and DDD compatible
  • 💾 Multi-Targeting - .NET 8, 9, and 10

📦 Installation

Option 1: Entity Framework Core Only

dotnet add package RepoKit.Core
dotnet add package RepoKit.EfCore

Option 2: Dapper Only

dotnet add package RepoKit.Core
dotnet add package RepoKit.Dapper

Option 3: Both EF Core and Dapper

dotnet add package RepoKit.Core
dotnet add package RepoKit.EfCore
dotnet add package RepoKit.Dapper

🚀 Quick Start

Step 1: Define Entity

using RepoKit.Core;

[AutoRepository]
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public decimal Price { get; set; }
    public bool IsActive { get; set; }
}

Step 2: Configure Services

Entity Framework Core Only:

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddDbContext<AppDbContext>()
    .AddAutoRepositoryEfCore<AppDbContext>()
    .AddAutoRepositories(typeof(Program).Assembly);

Dapper Only:

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddAutoRepositoryDapper(sp => 
        new SqlConnection("Server=localhost;Database=MyDb;Trusted_Connection=true;"))
    .AddAutoRepositories(typeof(Program).Assembly);

Both EF Core and Dapper:

var builder = WebApplication.CreateBuilder(args);

builder.Services
    .AddDbContext<AppDbContext>()
    .AddAutoRepositoryEfCore<AppDbContext>()
    .AddAutoRepositoryDapper(sp => 
        new SqlConnection("Server=localhost;Database=MyDb;Trusted_Connection=true;"))
    .AddAutoRepositories(typeof(Program).Assembly);

Step 3: Inject & Use

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private readonly IRepository<Product> _repo;

    public ProductsController(IRepository<Product> repo) => _repo = repo;

    [HttpGet("{id}")]
    public async Task<ActionResult<Product>> Get(int id)
    {
        var product = await _repo.GetByIdAsync(id);
        return product != null ? Ok(product) : NotFound();
    }

    [HttpPost]
    public async Task<ActionResult> Create(Product product)
    {
        await _repo.AddAsync(product);
        return Created($"products/{product.Id}", product);
    }

    [HttpPut("{id}")]
    public async Task<IActionResult> Update(int id, Product product)
    {
        var existing = await _repo.GetByIdAsync(id);
        if (existing == null) return NotFound();
        
        product.Id = id;
        await _repo.UpdateAsync(product);
        return NoContent();
    }

    [HttpDelete("{id}")]
    public async Task<IActionResult> Delete(int id)
    {
        await _repo.DeleteByIdAsync(id);
        return NoContent();
    }

    [HttpGet]
    public async Task<ActionResult<PagedResult<Product>>> GetAll(
        [FromQuery] int pageNumber = 1,
        [FromQuery] int pageSize = 10)
    {
        var result = await _repo.GetPagedAsync(
            new AllProductsSpec(), pageNumber, pageSize);
        return Ok(result);
    }
}

🔍 Advanced Usage

Specification Pattern

public class ActiveProductsSpec : BaseSpecification<Product>
{
    public ActiveProductsSpec(string? search = null)
    {
        AddCriteria(p => p.IsActive);
        
        if (search != null)
            AddCriteria(p => p.Name.Contains(search));
        
        ApplyOrderBy(p => p.Name);
        AddInclude(p => p.Category);
        AddInclude(p => p.Supplier);
        ApplyPaging(skip: 0, take: 10);
    }
}

var spec = new ActiveProductsSpec("laptop");
var products = await _repo.GetAsync(spec);
var paged = await _repo.GetPagedAsync(spec, pageNumber: 1, pageSize: 10);

Dapper with Raw SQL

public class TopSellingProductsSpec : BaseSpecification<Product>
{
    public TopSellingProductsSpec(int limit = 5)
    {
        UseRawSql(
            @"SELECT TOP @Limit p.* 
              FROM Products p
              INNER JOIN OrderItems oi ON p.Id = oi.ProductId
              GROUP BY p.Id, p.Name, p.Price
              ORDER BY COUNT(*) DESC",
            new { Limit = limit });
    }
}

var spec = new TopSellingProductsSpec(5);
var topProducts = await _repo.GetAsync(spec);

Unit of Work Pattern

public class ProductTransferService
{
    private readonly IRepository<Product> _productRepo;
    private readonly IRepository<Category> _categoryRepo;
    private readonly IUnitOfWork _unitOfWork;

    public async Task MoveProductsAsync(int fromCategoryId, int toCategoryId)
    {
        await _unitOfWork.BeginTransactionAsync();
        try
        {
            var spec = new ProductsByCategorySpec(fromCategoryId);
            var products = await _productRepo.GetAsync(spec);
            
            foreach (var product in products)
            {
                product.CategoryId = toCategoryId;
                await _productRepo.UpdateAsync(product);
            }
            
            await _unitOfWork.SaveChangesAsync();
            await _unitOfWork.CommitTransactionAsync();
        }
        catch
        {
            await _unitOfWork.RollbackTransactionAsync();
            throw;
        }
    }
}

Read-Only Repositories

[AutoRepository(ReadOnly = true)]
public class AuditLog
{
    public int Id { get; set; }
    public string Action { get; set; } = string.Empty;
    public DateTime Timestamp { get; set; }
}

private readonly IReadRepository<AuditLog> _auditRepo;
public async Task<IActionResult> History()
{
    var logs = await _auditRepo.GetAllAsync();
    return Ok(logs);
}

Custom Implementations

public class CustomProductRepository : DapperRepository<Product>
{
    public CustomProductRepository(IDbConnection connection) 
        : base(connection) { }
    
    protected override string GetTableName() => "tbl_Product";
    protected override string GetIdColumnName() => "ProductID";
}

[AutoRepository(CustomImplementation = typeof(CustomProductRepository))]
public class SpecialProduct { }

📊 Architecture

Project Structure

RepoKit.Core (Required)
├── IRepository<T>          - Full CRUD operations
├── IReadRepository<T>      - Read-only operations
├── IUnitOfWork             - Transaction management
├── ISpecification<T>       - Query specification
├── PagedResult<T>          - Paged result container
├── BaseSpecification<T>    - Base class for specifications
└── [AutoRepository]        - Entity registration attribute

RepoKit.EfCore (Optional)
├── EfRepository<T>         - Entity Framework implementation
├── EfUnitOfWork            - DbContext-based transactions
├── SpecificationEvaluator  - Converts specs to LINQ
└── ServiceCollectionExtensions

RepoKit.Dapper (Optional)
├── DapperRepository<T>     - Dapper implementation
├── DapperUnitOfWork        - SQL transaction management
└── ServiceCollectionExtensions

🎯 Best Practices

DO:

  • Use IReadRepository<T> for queries only
  • Create specifications for complex queries
  • Use Unit of Work for multi-repository operations
  • Always paginate large datasets
  • Use [AutoRepository(ReadOnly = true)] for audit entities

DON'T:

  • Use IRepository<T> where IReadRepository<T> suffices
  • Retrieve all rows without pagination
  • Pass raw SQL without parameters (SQL injection risk)

📋 API Reference

Method Returns Purpose
GetByIdAsync<TKey>(key) T? Get entity by primary key
GetAllAsync() IReadOnlyList<T> Get all entities
GetAsync(spec) IReadOnlyList<T> Get by specification
GetPagedAsync(spec, page, size) PagedResult<T> Get paginated results
CountAsync(spec) int Count matching entities
AnyAsync(spec) bool Check if any exists
AddAsync(entity) Task Add single entity
UpdateAsync(entity) Task Update entity
DeleteAsync(entity) Task Delete entity

⚙️ Requirements

  • .NET 8.0+ - Supports 8.0, 9.0, 10.0
  • C# 12+ - Using nullable reference types
  • Entity Framework Core 8.0+ - For RepoKit.EfCore
  • Dapper 2.1+ - For RepoKit.Dapper

📝 License

MIT License - See LICENSE for details.


🤝 Contributing

Contributions are welcome! See CONTRIBUTING.md for guidelines.


📚 Documentation


💬 Support


Made with ❤️ by Sourav Das

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
1.0.0 32 3/25/2026