GenericRepository.EFCore9 1.0.0

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

GenericRepository.EFCore

  • A clean, extensible, and dependency-free Generic Repository implementation based on SOLID principles and Clean Architecture.
    Supports Specification Pattern, Soft Delete, Paging, and Bulk Operations with EF Core 9+.
  • This package provides an Entity Framework Core implementation of the interfaces defined in GenericRepository.Abstractions.

๐Ÿ“ Projects

Project Description
GenericRepository.Abstractions Core interfaces for read/write/bulk repository operations. No external dependencies.
GenericRepository.EFCore EF Core implementation including specification support, paging, soft delete, and bulk operations.

โœ… Features

  • Clean architecture & SOLID-compliant
  • Fully async repository methods
  • Soft delete support (IsDeleted)
  • Full auditing support with ICreatableAuditable, IUpdatableAuditable, and IDeletableAuditable
  • Pagination with total count via PagedResult<T>
  • Specification pattern support
  • Bulk operations using EFCore.BulkExtensions
  • Efficient bulk inserts using batching
  • Dependency Injection ready via AddGenericRepository()
  • Transactional support

๐Ÿ› ๏ธ Requirements

  • .NET 9.0 or later
  • EF Core 9

๐Ÿ“ฆ Installation

dotnet add package GenericRepository.Abstractions
dotnet add package GenericRepository.EFCore

๐Ÿ”— Dependencies

  • GenericRepository.Abstractions
  • Microsoft.EntityFrameworkCore
  • EFCore.BulkExtensions

๐Ÿ•ต๏ธ Auditing Support

The EFCore implementation automatically handles audit fields if your entities implement:

Interface Automatically set on
ICreatableAuditable CreatedAt, CreatedBy during Add
IUpdatableAuditable UpdatedAt, UpdatedBy during Update
IDeletableAuditable DeletedAt, DeletedBy during Delete

Make sure to pass the current user context to support CreatedBy, UpdatedBy, etc.

Note: Bulk operations bypass SaveChangesAsync and do not trigger EF interceptors or audit tracking. You must apply auditing manually using interfaces like ICreatableAuditable.


๐Ÿงช Usage

// Register repository in DI
services.AddGenericRepository();

// Example usage in service
public class ProductService
{
    private readonly IRepository<Product> _repository;
    private readonly IBulkConfigProvider _bulkConfigProvider; // Optional, if you want using bulk operations. this is default config, also you can use custom config
    public ProductService(IRepository<Product> repository, IBulkConfigProvider bulkConfigProvider)
    {
        _repository = repository;
        _bulkConfigProvider = bulkConfigProvider;
    }

    public async Task<List<Product>> GetAllAsync()
    {
        return await _repository.GetListAsync();
    }

    public async Task<PagedResult<Product>> GetPagedAsync()
    {
        var spec = new ProductByCategorySpecification("Books");
        return await _repository.GetPagedAsync(spec, page: 1, pageSize: 10);
    }

    public async Task BulkInsertAsync(List<Product> products)
    {
        await _repository.BulkInsertAsync(products);
        await _repository.BulkInsertAsync(products, userId); // Required if auditing is enabled
    }

    public async Task<ProductResponse> AddAsync(ProductRequest request, CancellationToken cancellationToken = default)
    {
        var product = new Product
        {
            Name = request.Name,
            Price = request.Price
        };
        await _repository.AddAsync(product, cancellationToken);
        return new ProductResponse { Id = product.Id, Name = product.Name };
    }
}

public abstract class AuditableEntity : ICreatableAuditable<string>, IUpdatableAuditable<string?>
{
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    public string CreatedBy { get; set; } = string.Empty;
    public DateTime? UpdatedAt { get; set; }
    public string? UpdatedBy { get; set; }
}

public class ApplicationDbContext : DbContext
{
    // override SaveChangerAsync to configure aduiting fields. Note that: this didn't work with bulk operations
    public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        var entries = ChangeTracker.Entries<AuditableEntity>();

        foreach (var entityEntry in entries)
        {
            // Get the user ID dynamically at save time
            var userId = _contextAccessor.GetUserId();
            if (entityEntry.State == EntityState.Added)
            {
                entityEntry.Entity.CreatedBy = userId!;
            }
            else if (entityEntry.State == EntityState.Modified)
            {
                entityEntry.Entity.UpdatedAt = DateTime.UtcNow;
                entityEntry.Entity.UpdatedBy = userId;
            }
        }

        return base.SaveChangesAsync(cancellationToken);
    }
}

public class ProductByCategorySpecification() : Specification<Product>
{
    public ProductByCategorySpecification(string category)
    {
        AddCriteria(p => p.Category == category);
    }
}

๐Ÿ”ง Bulk Configuration (Optional)

You can override default EFCore.BulkExtensions settings:

public class CustomBulkConfigProvider : IBulkConfigProvider
{
    public BulkConfig GetBulkConfig()
    {
        return new BulkConfig
        {
            BatchSize = 500, // Default batch size for bulk operations 1000
            PreserveInsertOrder = true
        };
    }
}

๐Ÿ“œ License

MIT License

Product Compatible and additional computed target framework versions.
.NET 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 was computed.  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 151 6/4/2025