Bounteous.Data
0.0.26
See the version list below for details.
dotnet add package Bounteous.Data --version 0.0.26
NuGet\Install-Package Bounteous.Data -Version 0.0.26
<PackageReference Include="Bounteous.Data" Version="0.0.26" />
<PackageVersion Include="Bounteous.Data" Version="0.0.26" />
<PackageReference Include="Bounteous.Data" />
paket add Bounteous.Data --version 0.0.26
#r "nuget: Bounteous.Data, 0.0.26"
#:package Bounteous.Data@0.0.26
#addin nuget:?package=Bounteous.Data&version=0.0.26
#tool nuget:?package=Bounteous.Data&version=0.0.26
Bounteous.Data
A comprehensive Entity Framework Core data access library for .NET 10+ applications that provides enhanced auditing, flexible ID strategies, read-only entity protection, and simplified data operations.
Overview
Bounteous.Data enhances Entity Framework Core with enterprise-grade features for clean architecture and domain-driven design patterns. It provides automatic auditing, flexible identity strategies, read-only entity protection, and simplified data access patterns.
Key Features
- ✅ Automatic Auditing - CreatedBy, ModifiedBy, Version tracking with zero boilerplate
- ✅ Flexible ID Strategies - Support for Guid, long, int for both entities and users
- ✅ Read-Only Protection - Two-layer defense (immediate + deferred validation)
- ✅ ReadOnlyDbSet - Fail-fast wrapper that throws exceptions immediately on write operations
- ✅ Automatic User Resolution - IIdentityProvider integration for seamless auth
- ✅ Soft Delete Support - Logical deletion maintaining referential integrity
- ✅ Query Extensions - WhereIf, IncludeIf, pagination, FindById helpers
- ✅ Observer Pattern - Entity lifecycle events for logging and business rules
- ✅ Type Safety - Compile-time checking for ID types and audit fields
Installation
dotnet add package Bounteous.Data
Or via Package Manager Console:
Install-Package Bounteous.Data
Quick Implementation
1. Configure Services
using Bounteous.Core.Extensions;
public void ConfigureServices(IServiceCollection services)
{
// Auto-register all services from the assembly
services.AutoRegister(typeof(Program).Assembly);
// Register your connection string provider
services.AddSingleton<IConnectionStringProvider, MyConnectionStringProvider>();
// Register your DbContext factory
services.AddScoped<IDbContextFactory<MyDbContext, Guid>, MyDbContextFactory>();
}
2. Create Your Entities
using Bounteous.Data.Domain.Entities;
// Modern entity with Guid ID and full audit support
public class Customer : AuditBase
{
public string Name { get; set; } = string.Empty;
public string Email { get; set; } = string.Empty;
}
// Legacy entity with long ID
public class LegacyProduct : AuditBase<long, Guid>
{
public string Name { get; set; } = string.Empty;
public decimal Price { get; set; }
}
// Read-only entity (queries only, no CUD operations)
public class LegacySystem : ReadOnlyEntityBase<int>
{
public string SystemName { get; set; } = string.Empty;
}
3. Create Your DbContext
using Bounteous.Data;
using Bounteous.Data.Domain.ReadOnly;
public class MyDbContext : DbContextBase<Guid>
{
public MyDbContext(
DbContextOptions options,
IDbContextObserver? observer,
IIdentityProvider<Guid> identityProvider)
: base(options, observer, identityProvider)
{
}
public DbSet<Customer> Customers { get; set; }
public DbSet<LegacyProduct> LegacyProducts { get; set; }
// ReadOnlyDbSet for fail-fast protection
public ReadOnlyDbSet<LegacySystem, int> LegacySystems
=> Set<LegacySystem>().AsReadOnly<LegacySystem, int>();
protected override void RegisterModels(ModelBuilder modelBuilder)
{
// Configure legacy entities
modelBuilder.Entity<LegacyProduct>()
.Property(p => p.Id)
.ValueGeneratedNever();
}
}
4. Use in Your Services
public class CustomerService
{
private readonly IDbContextFactory<MyDbContext, Guid> contextFactory;
public CustomerService(IDbContextFactory<MyDbContext, Guid> contextFactory)
=> this.contextFactory = contextFactory;
public async Task<Customer> CreateCustomerAsync(string name, string email)
{
using var context = contextFactory.Create();
// No need to call WithUserId() - IIdentityProvider handles it automatically!
var customer = new Customer { Name = name, Email = email };
context.Customers.Add(customer);
await context.SaveChangesAsync();
// Audit fields automatically populated:
// - customer.Id = new Guid
// - customer.CreatedBy = current user ID from IIdentityProvider
// - customer.CreatedOn = DateTime.UtcNow
// - customer.Version = 1
return customer;
}
}
What Gets Automated
When you use AuditBase or AuditBase<TId, TUserId>, these fields are automatically managed:
// On Create:
entity.CreatedBy = currentUserId; // From IIdentityProvider or WithUserId()
entity.CreatedOn = DateTime.UtcNow;
entity.ModifiedBy = currentUserId;
entity.ModifiedOn = DateTime.UtcNow;
entity.Version = 1;
// On Update:
entity.ModifiedBy = currentUserId;
entity.ModifiedOn = DateTime.UtcNow;
entity.Version++; // Incremented for optimistic concurrency
Read-Only Entity Protection
Bounteous.Data provides two layers of protection for read-only entities:
Layer 1: ReadOnlyEntityBase (Deferred Validation)
public class LegacySystem : ReadOnlyEntityBase<int>
{
public string SystemName { get; set; } = string.Empty;
}
// Error occurs at SaveChanges()
context.LegacySystems.Add(new LegacySystem { Id = 1 });
await context.SaveChangesAsync(); // ❌ Throws ReadOnlyEntityException here
Layer 2: ReadOnlyDbSet (Immediate Validation)
public ReadOnlyDbSet<LegacySystem, int> LegacySystems
=> Set<LegacySystem>().AsReadOnly<LegacySystem, int>();
// Error occurs immediately
context.LegacySystems.Add(new LegacySystem { Id = 1 }); // ❌ Throws immediately
Benefits:
- ✅ Fail-fast behavior - errors caught at the point of invalid operation
- ✅ Clear intent - explicit read-only semantics in code
- ✅ Defense in depth - two layers of protection
Testing with Read-Only Entities
For unit tests that need to seed read-only entities into an in-memory database, use the fluent API:
using Bounteous.Data.Extensions;
[Fact]
public async Task Test_With_ReadOnly_Data()
{
await using var context = CreateTestContext();
// Suppress validation during test data seeding - fluent API
using var scope = context.SuppressReadOnlyValidation();
context.LegacySystems.Add(new LegacySystem
{
Id = 1,
SystemName = "Test System"
});
await context.SaveChangesAsync(); // ✅ Succeeds within scope
// Validation automatically re-enabled after scope disposal
}
Alternative syntax:
// Direct instantiation (still supported)
using (new ReadOnlyValidationScope())
{
// ...
}
Key Points:
- ✅ Validation is always enforced by default in production
- ✅ Scope provides explicit, self-documenting test intent
- ✅ Thread-safe using
AsyncLocal<T>for async operations - ✅ Automatically re-enables validation when disposed
Read-Only Request Workflows
For query-only operations (GET endpoints, reports, list views), use the fluent API to enforce that no data modifications occur:
using Bounteous.Data.Extensions;
public class CompanyService
{
public async Task<List<Company>> GetCompaniesAsync()
{
await using var context = _contextFactory.Create();
// Enforce read-only mode for this entire request - fluent API
using var scope = context.EnforceReadOnly();
// Only queries allowed
return await context.Companies
.OrderBy(c => c.Name)
.ToListAsync();
// Any SaveChanges() call will throw InvalidOperationException
}
}
Alternative syntax:
// Direct instantiation (still supported)
using (new ReadOnlyRequestScope())
{
// ...
}
Benefits:
- ✅ Prevents accidental modifications in query-only workflows
- ✅ Fail-fast protection - catches bugs at SaveChanges
- ✅ Self-documenting code - clearly marks read-only operations
- ✅ Thread-safe with
AsyncLocal<T>for concurrent requests
Comparison:
| Feature | ReadOnlyValidationScope | ReadOnlyRequestScope |
|---|---|---|
| Purpose | Suppress validation for test seeding | Enforce read-only for query operations |
| When to use | Unit tests only | Production query endpoints |
| Effect | Allows modifications to readonly entities | Blocks ALL modifications |
| Throws on SaveChanges | No (suppresses) | Yes (enforces) |
Comprehensive Documentation
For detailed documentation including:
- Complete API reference
- Advanced scenarios (mixed ID strategies, custom observers, etc.)
- IIdentityProvider implementation examples
- Query extensions and helpers
- Value converters
- Best practices and migration guides
See the comprehensive developer documentation
Additional Resources
Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests for new functionality (xUnit preferred)
- Ensure all tests pass:
dotnet test - Submit a pull request
License
This project is licensed under the terms specified in the LICENSE file.
| Product | Versions 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. |
-
net10.0
- Bounteous.Core (>= 0.0.18)
- Microsoft.EntityFrameworkCore (>= 10.0.1)
- Microsoft.EntityFrameworkCore.Relational (>= 10.0.1)
- Microsoft.Extensions.Configuration.Abstractions (>= 10.0.1)
NuGet packages (6)
Showing the top 5 NuGet packages that depend on Bounteous.Data:
| Package | Downloads |
|---|---|
|
Bounteous.Data.SqlServer
Package Description |
|
|
Bounteous.xUnit.Accelerator
Package Description |
|
|
Bounteous.Data.Extensions
⚠️ NOT INTENDED FOR PRODUCTION USE ⚠️ Developer utilities for Bounteous.Data including ReadOnlyDbSetExtensions for creating test objects. WARNING: This package bypasses read-only validation and should only be used in: - Unit test projects - Data migration projects - Development environments DO NOT USE IN PRODUCTION CODE. |
|
|
Bounteous.Data.MySQL
Package Description |
|
|
Bounteous.Data.PostgreSQL
Package Description |
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.0.29 | 1,842 | 4/13/2026 |
| 0.0.28 | 641 | 3/16/2026 |
| 0.0.27 | 228 | 3/16/2026 |
| 0.0.26 | 1,272 | 1/11/2026 |
| 0.0.25 | 234 | 1/11/2026 |
| 0.0.24 | 249 | 1/10/2026 |
| 0.0.23 | 255 | 1/10/2026 |
| 0.0.22 | 235 | 1/10/2026 |
| 0.0.21 | 899 | 1/9/2026 |
| 0.0.20 | 251 | 1/8/2026 |
| 0.0.19 | 246 | 1/8/2026 |
| 0.0.18 | 236 | 1/8/2026 |
| 0.0.17 | 402 | 1/7/2026 |
| 0.0.16 | 432 | 10/7/2025 |
| 0.0.15 | 204 | 10/7/2025 |
| 0.0.14 | 240 | 9/29/2025 |
| 0.0.13 | 243 | 9/29/2025 |
| 0.0.12 | 1,837 | 5/4/2025 |
| 0.0.11 | 185 | 5/3/2025 |
| 0.0.10 | 145 | 5/3/2025 |