Chd.AutoUI.EF 8.0.3

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

Chd.AutoUI.EF – Generic Repository for EF Core

Stop writing the same CRUD data-access code for every entity. Register once, use everywhere.

NuGet License: MIT


📝 Table of Contents


About

Chd.AutoUI.EF provides a generic repository implementation built on EF Core. It is designed to pair with Chd.AutoUI but works independently in any ASP.NET Core project.

The motivation is simple: in CRUD-heavy applications you end up writing the same data-access code over and over — GetAll, GetById, Add, Update, Delete. This package puts all of that behind a single generic interface. You register it once and DI takes care of injecting the right DbSet<T> for each entity.


🎯 Features

  • One registration covers all entity types via open generics (IGenericRepository<>)
  • Full async support — all methods return Task
  • FindAsync accepts LINQ expressions for filtered queries without raw SQL
  • Works with any EF Core-supported database (PostgreSQL, SQL Server, SQLite, MySQL, etc.)
  • Supports different ID types: int, long, Guid, or any other type EF Core understands
  • GenericRepository<T> is designed to be extended — inherit and add entity-specific methods

📦 Installation

dotnet add package Chd.AutoUI.EF

EF Core and a database provider are required separately:

dotnet add package Microsoft.EntityFrameworkCore
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL   # PostgreSQL
# or
dotnet add package Microsoft.EntityFrameworkCore.SqlServer  # SQL Server
# or
dotnet add package Microsoft.EntityFrameworkCore.Sqlite     # SQLite

🚀 Quick Start

1. Create Your Entity

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public decimal Price { get; set; }
    public int Stock { get; set; }
    public bool IsActive { get; set; } = true;
    public DateTime CreatedDate { get; set; } = DateTime.UtcNow;
}

2. Register in Program.cs

builder.Services.AddDbContext<AppDbContext>(options =>
    options.UseNpgsql(builder.Configuration.GetConnectionString("DefaultConnection")));

// One line registers IGenericRepository<T> for any entity type
builder.Services.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>));

3. Inject and Use in a Controller

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

    public ProductsController(IGenericRepository<Product> repo)
    {
        _repo = repo;
    }

    [HttpGet]
    public async Task<IActionResult> GetAll() =>
        Ok(await _repo.GetAllAsync());

    [HttpGet("{id}")]
    public async Task<IActionResult> GetById(int id)
    {
        var item = await _repo.GetByIdAsync(id);
        return item == null ? NotFound() : Ok(item);
    }

    [HttpPost]
    public async Task<IActionResult> Create([FromBody] Product product) =>
        CreatedAtAction(nameof(GetById), new { id = product.Id }, await _repo.AddAsync(product));

    [HttpPut("{id}")]
    public async Task<IActionResult> Update(int id, [FromBody] Product product)
    {
        if (id != product.Id) return BadRequest();
        return Ok(await _repo.UpdateAsync(product));
    }

    [HttpDelete("{id}")]
    public async Task<IActionResult> Delete(int id) =>
        await _repo.DeleteAsync(id) ? Ok() : NotFound();
}

The same controller pattern applies to every other entity — just change the type parameter.


🔌 IGenericRepository Interface

public interface IGenericRepository<TEntity> where TEntity : class
{
    /// <summary>Returns the entity with the given primary key, or null if not found.</summary>
    Task<TEntity?> GetByIdAsync(object id);

    /// <summary>Returns all records in the table.</summary>
    Task<List<TEntity>> GetAllAsync();

    /// <summary>Returns records matching the given LINQ expression.</summary>
    Task<List<TEntity>> FindAsync(Expression<Func<TEntity, bool>> predicate);

    /// <summary>Adds a new record and returns the saved entity (with generated Id).</summary>
    Task<TEntity> AddAsync(TEntity entity);

    /// <summary>Updates an existing record and returns the saved entity.</summary>
    Task<TEntity> UpdateAsync(TEntity entity);

    /// <summary>Deletes the record with the given primary key. Returns true if deleted, false if not found.</summary>
    Task<bool> DeleteAsync(object id);

    /// <summary>Returns the total row count for the table.</summary>
    Task<int> CountAsync();
}

🔍 Filtering with FindAsync

FindAsync accepts any LINQ predicate expression, so you can do most queries without stepping outside the repository:

// Active products with stock above a threshold
var available = await _repo.FindAsync(p => p.IsActive && p.Stock > 0);

// By exact match
var electronics = await _repo.FindAsync(p => p.CategoryId == 3);

// Contains search on a string field
var results = await _repo.FindAsync(p => p.Name.Contains("phone"));

// Combine conditions
var featured = await _repo.FindAsync(p => p.IsActive && p.IsFeatured && p.Price < 1000);

For queries that require Include, custom ordering, or pagination, extend the repository (see below).


🔧 Extending the Repository

When you need queries beyond what FindAsync covers, inherit from GenericRepository<T>:

public class ProductRepository : GenericRepository<Product>
{
    public ProductRepository(AppDbContext context) : base(context) { }

    public async Task<List<Product>> GetLowStockAsync(int threshold) =>
        await _dbSet
            .Where(p => p.IsActive && p.Stock < threshold)
            .OrderBy(p => p.Stock)
            .ToListAsync();

    public async Task<List<Product>> GetByCategoryAsync(int categoryId) =>
        await _dbSet
            .Include(p => p.Category)
            .Where(p => p.CategoryId == categoryId && p.IsActive)
            .ToListAsync();

    public async Task<(List<Product> Items, int Total)> GetPagedAsync(int page, int pageSize) =>
        (
            await _dbSet.Skip((page - 1) * pageSize).Take(pageSize).ToListAsync(),
            await _dbSet.CountAsync()
        );
}

Register the custom repository for Product specifically — DI will use it for that type and fall back to the generic implementation for everything else:

// Specific entity uses the extended repository
builder.Services.AddScoped<IGenericRepository<Product>, ProductRepository>();

// All other entities use the generic implementation
builder.Services.AddScoped(typeof(IGenericRepository<>), typeof(GenericRepository<>));

Project Description
Chd.AutoUI Attribute-driven UI metadata for .NET — works great alongside this package
chd-auto-ui-react React components for dynamic forms and grids
AutoUI Demo Full POS demo using both packages together
All Demo Projects All CHD examples, benchmarks and test projects

📄 License

MIT

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 was computed.  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
8.0.3 40 4/6/2026
8.0.2 39 4/5/2026
8.0.1 43 4/5/2026
8.0.0 76 3/24/2026
1.0.0 74 3/24/2026