RepoKit.Dapper
1.0.0
dotnet add package RepoKit.Dapper --version 1.0.0
NuGet\Install-Package RepoKit.Dapper -Version 1.0.0
<PackageReference Include="RepoKit.Dapper" Version="1.0.0" />
<PackageVersion Include="RepoKit.Dapper" Version="1.0.0" />
<PackageReference Include="RepoKit.Dapper" />
paket add RepoKit.Dapper --version 1.0.0
#r "nuget: RepoKit.Dapper, 1.0.0"
#:package RepoKit.Dapper@1.0.0
#addin nuget:?package=RepoKit.Dapper&version=1.0.0
#tool nuget:?package=RepoKit.Dapper&version=1.0.0
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.
✨ 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>whereIReadRepository<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
- Quick Start Guide
- CI/CD Pipeline
- Publishing Guide
- Branch Protection
- Contributing Guidelines
- Changelog
💬 Support
Made with ❤️ by Sourav Das
| 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
- Dapper (>= 2.1.28)
- RepoKit.Core (>= 1.0.0)
-
net8.0
- Dapper (>= 2.1.28)
- RepoKit.Core (>= 1.0.0)
-
net9.0
- Dapper (>= 2.1.28)
- RepoKit.Core (>= 1.0.0)
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 |