OakIdeas.GenericRepository 0.0.7-alpha

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

GenericRepository

Build & Test Deploy to NuGet CodeQL

A versatile and extensible implementation of the repository pattern for CRUD operations with support for middleware pipelines, multiple storage backends, and advanced querying.

Features

  • Generic Repository Interface - Type-safe repository operations with support for custom key types
  • Multiple Implementations:
    • In-Memory Repository (Dictionary-based, perfect for testing)
    • Entity Framework Core Repository
  • Middleware Pipeline - Extensible middleware architecture for cross-cutting concerns
  • Soft Delete Support - Built-in soft delete functionality
  • Query Object Pattern - Fluent API for building complex queries
  • Specification Pattern - Reusable business rules and query logic
  • Async Enumerable Support - Stream large datasets without loading everything into memory
  • Type-Safe Navigation - Type-safe eager loading of related entities

Packages

  • OakIdeas.GenericRepository - Core interfaces and base functionality
  • OakIdeas.GenericRepository.Memory - In-memory repository implementation
  • OakIdeas.GenericRepository.EntityFrameworkCore - EF Core repository implementation
  • OakIdeas.GenericRepository.Middleware - Middleware infrastructure and standard middleware

Basic Usage

using OakIdeas.GenericRepository;
using OakIdeas.GenericRepository.Models;

public class Customer : EntityBase
{
    public string Name { get; set; }
    public string Email { get; set; }
}

// Create a repository instance
var repository = new MemoryGenericRepository<Customer>();

// Create (C)
var customer = await repository.Insert(new() 
{ 
    Name = "John Doe",
    Email = "john@example.com"
});

// Retrieve (R)
var foundCustomer = await repository.Get(customer.ID);

// Or retrieve with filtering
var customers = await repository.Get(
    filter: c => c.Name.Contains("John"),
    orderBy: q => q.OrderBy(c => c.Name)
);

// Update (U)
customer.Name = "Jane Doe";
await repository.Update(customer);

// Delete (D)
await repository.Delete(customer.ID);

Middleware Architecture

The middleware system provides a powerful way to add cross-cutting concerns to your repository operations.

Configuring Options

using OakIdeas.GenericRepository.Core;
using OakIdeas.GenericRepository.Middleware.Extensions;

// Create options with middleware support
var options = new RepositoryOptions()
    .WithLogging(enabled: true)
    .WithPerformanceTracking(enabled: true)
    .WithValidation(enabled: true);

var repository = new MemoryGenericRepository<Customer>(options);

Standard Middleware

Logging Middleware

Automatically logs repository operations:

using OakIdeas.GenericRepository.Middleware;
using OakIdeas.GenericRepository.Middleware.Standard;

var pipeline = new MiddlewarePipeline<Customer, int>();

pipeline.Use(new LoggingMiddleware<Customer, int>(
    logger: message => Console.WriteLine(message),
    includeTimings: true
));
Validation Middleware

Validates entities before operations:

var validationMiddleware = new ValidationMiddleware<Customer, int>(
    validator: customer => 
    {
        if (string.IsNullOrEmpty(customer.Email))
            return (false, "Email is required");
        
        if (!customer.Email.Contains("@"))
            return (false, "Invalid email format");
        
        return (true, null);
    }
);

pipeline.Use(validationMiddleware);
Performance Middleware

Tracks operation performance:

var performanceMiddleware = new PerformanceMiddleware<Customer, int>(
    metricCollector: (operationName, elapsedMs) => 
    {
        Console.WriteLine($"{operationName} took {elapsedMs}ms");
    },
    warningThresholdMs: 1000 // Warn if operation takes more than 1 second
);

pipeline.Use(performanceMiddleware);

Custom Middleware

Create your own middleware by implementing IRepositoryMiddleware<TEntity, TKey>:

public class AuditMiddleware<TEntity, TKey> : IRepositoryMiddleware<TEntity, TKey>
    where TEntity : class
    where TKey : notnull
{
    private readonly IAuditLogger _auditLogger;

    public AuditMiddleware(IAuditLogger auditLogger)
    {
        _auditLogger = auditLogger;
    }

    public async Task InvokeAsync(
        RepositoryContext<TEntity, TKey> context,
        RepositoryMiddlewareDelegate<TEntity, TKey> next)
    {
        // Before operation
        _auditLogger.LogBefore(context.Operation, context.Entity);

        await next(context);

        // After operation
        _auditLogger.LogAfter(context.Operation, context.Result, context.Success);
    }
}

Advanced Querying

Query Object Pattern

using OakIdeas.GenericRepository;

var query = new Query<Customer>()
    .Where(c => c.Name.StartsWith("J"))
    .Sort(q => q.OrderByDescending(c => c.ID))
    .Include(c => c.Orders)
    .Paged(page: 1, pageSize: 10)
    .WithNoTracking();

var results = await repository.Get(query);

Specification Pattern

using OakIdeas.GenericRepository.Specifications;

public class ActiveCustomerSpecification : Specification<Customer>
{
    public override Expression<Func<Customer, bool>> ToExpression()
    {
        return customer => customer.IsActive && !customer.IsDeleted;
    }
}

public class CustomerByNameSpecification : Specification<Customer>
{
    private readonly string _name;

    public CustomerByNameSpecification(string name)
    {
        _name = name;
    }

    public override Expression<Func<Customer, bool>> ToExpression()
    {
        return customer => customer.Name.Contains(_name);
    }
}

// Use specifications
var activeCustomers = await repository.Get(
    filter: new ActiveCustomerSpecification()
);

// Combine specifications
var activeJohns = new ActiveCustomerSpecification()
    .And(new()ByNameSpecification("John"));

var results = await repository.Get(filter: activeJohns);

Soft Delete Support

using OakIdeas.GenericRepository;
using OakIdeas.GenericRepository.Models;

public class Customer : SoftDeletableEntity
{
    public string Name { get; set; }
}

var repository = new SoftDeleteMemoryRepository<Customer>();

// Soft delete - marks as deleted but doesn't remove from storage
await repository.Delete(customer);

// Normal queries automatically exclude soft-deleted entities
var activeCustomers = await repository.Get();

// Include soft-deleted entities
var allCustomers = await repository.GetIncludingDeleted();

// Restore a soft-deleted entity
await repository.Restore(customer);

// Permanently delete
await repository.PermanentlyDelete(customer);

Entity Framework Core Usage

using Microsoft.EntityFrameworkCore;
using OakIdeas.GenericRepository.EntityFrameworkCore;

public class MyDbContext : DbContext
{
    public DbSet<Customer> Customers { get; set; }
}

var context = new MyDbContext(options);
var repository = new EntityFrameworkCoreRepository<Customer, MyDbContext>(context);

// Use the same repository interface
var customers = await repository.Get(
    filter: c => c.IsActive,
    orderBy: q => q.OrderBy(c => c.Name),
    includeProperties: "Orders,Address"
);

Batch Operations

// Insert multiple entities
var newCustomers = new List<Customer>
{
    new() { Name = "Alice" },
    new() { Name = "Bob" },
    new() { Name = "Charlie" }
};
var inserted = await repository.InsertRange(newCustomers);

// Update multiple entities
var updated = await repository.UpdateRange(newCustomers);

// Delete multiple entities
var deletedCount = await repository.DeleteRange(newCustomers);

// Delete by filter
var deletedByFilter = await repository.DeleteRange(c => c.IsActive == false);

Async Enumerable for Large Datasets

// Stream results without loading everything into memory
await foreach (var customer in repository.GetAsyncEnumerable(
    filter: c => c.CreatedDate > DateTime.UtcNow.AddYears(-1),
    orderBy: q => q.OrderBy(c => c.Name)))
{
    // Process each customer one at a time
    await ProcessCustomerAsync(customer);
}

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

For detailed contribution guidelines, see docs/contributing.md.

Documentation

For AI Assistants & Developers

License

This project is licensed under the terms specified in the LICENSE file.

Product Compatible and additional computed target framework versions.
.NET 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 (3)

Showing the top 3 NuGet packages that depend on OakIdeas.GenericRepository:

Package Downloads
OakIdeas.GenericRepository.EntityFrameworkCore

A very simple extention to OakIdeas.GenericRepository that adds support for EF Core

OakIdeas.GenericRepository.Middleware

Middleware infrastructure for OakIdeas.GenericRepository - enables extensible pipeline processing for repository operations.

OakIdeas.GenericRepository.Memory

In-memory implementation of OakIdeas.GenericRepository - suitable for testing and development scenarios.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.0.7-alpha 33 1/9/2026
0.0.6-alpha 40 1/8/2026
0.0.5.1-alpha 536 7/28/2020
0.0.5-alpha 729 7/24/2020

- Generic interface
- EntityBase
- Memory Repository (Dictionary based)