Acontplus.Persistence.Common
1.1.3
dotnet add package Acontplus.Persistence.Common --version 1.1.3
NuGet\Install-Package Acontplus.Persistence.Common -Version 1.1.3
<PackageReference Include="Acontplus.Persistence.Common" Version="1.1.3" />
<PackageVersion Include="Acontplus.Persistence.Common" Version="1.1.3" />
<PackageReference Include="Acontplus.Persistence.Common" />
paket add Acontplus.Persistence.Common --version 1.1.3
#r "nuget: Acontplus.Persistence.Common, 1.1.3"
#:package Acontplus.Persistence.Common@1.1.3
#addin nuget:?package=Acontplus.Persistence.Common&version=1.1.3
#tool nuget:?package=Acontplus.Persistence.Common&version=1.1.3
Acontplus.Persistence.Common
Advanced persistence abstractions and infrastructure. Includes generic repository patterns, context factory, connection string providers, and multi-provider support for SQL Server, PostgreSQL, and other databases with enterprise-ready abstractions.
🚀 Features
🏗️ Core Abstractions
- Generic Repository Pattern - Type-safe data access with cutting-edge C# features
- Context Factory - Flexible database context creation and management
- Connection String Provider - Hierarchical and environment-based connection management
- Multi-Provider Support - SQL Server, PostgreSQL, and extensible for other databases
- Enterprise Patterns - Unit of work, specification pattern, and audit trail support
🔧 Contemporary Architecture
- .NET 9+ Compatible - Latest C# features and performance optimizations
- Async/Await Support - Full asynchronous operation support
- Dependency Injection - Seamless integration with Microsoft DI container
- Configuration Driven - Flexible configuration through appsettings.json
- Error Handling - Comprehensive error handling with domain mapping
📦 Installation
NuGet Package Manager
Install-Package Acontplus.Persistence.Common
.NET CLI
dotnet add package Acontplus.Persistence.Common
PackageReference
<PackageReference Include="Acontplus.Persistence.Common" Version="1.1.0" />
🎯 Quick Start
1. Register Services in DI
using Acontplus.Persistence.Common;
// In Program.cs or Startup.cs
builder.Services.AddSingleton<IConnectionStringProvider, ConfigurationConnectionStringProvider>();
builder.Services.AddSingleton<IDbContextFactory<MyDbContext>, DbContextFactory<MyDbContext>>();
2. Configure Connection Strings
{
"ConnectionStrings": {
"DefaultConnection": "Server=localhost;Database=MyApp;Trusted_Connection=true;",
"TenantA": "Server=localhost;Database=TenantA;Trusted_Connection=true;",
"TenantB": "Server=localhost;Database=TenantB;Trusted_Connection=true;"
}
}
3. Use in Your Application
public class ProductService
{
private readonly IDbContextFactory<MyDbContext> _contextFactory;
private readonly IConnectionStringProvider _connectionProvider;
public ProductService(
IDbContextFactory<MyDbContext> contextFactory,
IConnectionStringProvider connectionProvider)
{
_contextFactory = contextFactory;
_connectionProvider = connectionProvider;
}
public async Task<IEnumerable<Product>> GetProductsAsync(string tenantId = null)
{
var context = _contextFactory.GetContext(tenantId);
var repository = new BaseRepository<Product>(context);
return await repository.FindAsync(p => p.IsActive);
}
}
🔧 Advanced Usage
Multi-Tenant Database Access
public class MultiTenantService
{
private readonly IDbContextFactory<MyDbContext> _contextFactory;
public MultiTenantService(IDbContextFactory<MyDbContext> contextFactory)
{
_contextFactory = contextFactory;
}
public async Task<Product> GetProductAsync(int productId, string tenantId)
{
// Get context for specific tenant
var context = _contextFactory.GetContext(tenantId);
var repository = new BaseRepository<Product>(context);
return await repository.GetByIdAsync(productId);
}
public async Task<IEnumerable<Product>> GetProductsForAllTenantsAsync()
{
var allProducts = new List<Product>();
var tenants = new[] { "TenantA", "TenantB", "TenantC" };
foreach (var tenant in tenants)
{
var context = _contextFactory.GetContext(tenant);
var repository = new BaseRepository<Product>(context);
var products = await repository.FindAsync(p => p.IsActive);
allProducts.AddRange(products);
}
return allProducts;
}
}
Custom Connection String Provider
public class CustomConnectionStringProvider : IConnectionStringProvider
{
private readonly IConfiguration _configuration;
private readonly IHttpContextAccessor _httpContextAccessor;
public CustomConnectionStringProvider(
IConfiguration configuration,
IHttpContextAccessor httpContextAccessor)
{
_configuration = configuration;
_httpContextAccessor = httpContextAccessor;
}
public string GetConnectionString(string name)
{
// Get tenant from HTTP context
var tenant = _httpContextAccessor.HttpContext?.User?.FindFirst("TenantId")?.Value;
if (!string.IsNullOrEmpty(tenant))
{
return _configuration.GetConnectionString($"{name}_{tenant}");
}
return _configuration.GetConnectionString(name);
}
}
Repository with Specifications
public class ProductRepository : BaseRepository<Product>
{
public ProductRepository(DbContext context) : base(context) { }
public async Task<IEnumerable<Product>> GetActiveProductsByCategoryAsync(int categoryId)
{
var spec = new ActiveProductsByCategorySpecification(categoryId);
return await FindWithSpecificationAsync(spec);
}
public async Task<PagedResult<Product>> GetPagedProductsAsync(PaginationDto pagination)
{
var spec = new ProductPaginationSpecification(pagination);
return await GetPagedAsync(spec);
}
}
public class ActiveProductsByCategorySpecification : BaseSpecification<Product>
{
public ActiveProductsByCategorySpecification(int categoryId)
: base(p => p.IsActive && p.CategoryId == categoryId)
{
AddInclude(p => p.Category);
AddOrderBy(p => p.Name);
}
}
📊 Configuration Options
Connection String Provider Options
public class ConnectionStringOptions
{
public string DefaultConnection { get; set; } = string.Empty;
public Dictionary<string, string> TenantConnections { get; set; } = new();
public bool UseEnvironmentVariables { get; set; } = true;
public string EnvironmentPrefix { get; set; } = "DB_";
}
Context Factory Options
public class ContextFactoryOptions
{
public bool EnableRetryOnFailure { get; set; } = true;
public int MaxRetryCount { get; set; } = 3;
public TimeSpan RetryDelay { get; set; } = TimeSpan.FromSeconds(5);
public bool EnableDetailedErrors { get; set; } = false;
public bool EnableSensitiveDataLogging { get; set; } = false;
}
🔍 Best Practices
1. Connection String Management
// Use hierarchical configuration
var connectionString = _connectionProvider.GetConnectionString("DefaultConnection");
// Handle missing connections gracefully
if (string.IsNullOrEmpty(connectionString))
{
throw new InvalidOperationException("Connection string 'DefaultConnection' not found");
}
2. Context Lifecycle Management
public class UnitOfWork : IDisposable
{
private readonly DbContext _context;
private readonly BaseRepository<Product> _productRepository;
private readonly BaseRepository<Category> _categoryRepository;
public UnitOfWork(IDbContextFactory<MyDbContext> contextFactory, string tenantId = null)
{
_context = contextFactory.GetContext(tenantId);
_productRepository = new BaseRepository<Product>(_context);
_categoryRepository = new BaseRepository<Category>(_context);
}
public BaseRepository<Product> Products => _productRepository;
public BaseRepository<Category> Categories => _categoryRepository;
public async Task<int> SaveChangesAsync()
{
return await _context.SaveChangesAsync();
}
public void Dispose()
{
_context?.Dispose();
}
}
3. Error Handling
public async Task<Result<Product>> GetProductSafelyAsync(int id)
{
try
{
var context = _contextFactory.GetContext();
var repository = new BaseRepository<Product>(context);
var product = await repository.GetByIdAsync(id);
return product is not null
? Result<Product>.Success(product)
: Result<Product>.Failure(DomainError.NotFound("PRODUCT_NOT_FOUND", $"Product {id} not found"));
}
catch (Exception ex)
{
return Result<Product>.Failure(DomainError.Internal("DATABASE_ERROR", ex.Message));
}
}
📚 API Reference
IConnectionStringProvider
public interface IConnectionStringProvider
{
string GetConnectionString(string name);
}
IDbContextFactory<T>
public interface IDbContextFactory<T> where T : DbContext
{
T GetContext(string tenantId = null);
T GetContext(IConnectionStringProvider connectionProvider, string connectionName);
}
BaseRepository<T>
public class BaseRepository<T> : IRepository<T> where T : class
{
public BaseRepository(DbContext context);
// Async operations
public Task<T?> GetByIdAsync(int id);
public Task<IEnumerable<T>> FindAsync(Expression<Func<T, bool>> predicate);
public Task<T> AddAsync(T entity);
public Task UpdateAsync(T entity);
public Task DeleteAsync(T entity);
// Specification pattern
public Task<IEnumerable<T>> FindWithSpecificationAsync(ISpecification<T> spec);
public Task<PagedResult<T>> GetPagedAsync(ISpecification<T> spec);
}
🔧 Dependencies
- .NET 9.0+ - Advanced .NET framework
- Entity Framework Core - ORM and data access
- Microsoft.Extensions.Configuration - Configuration management
- Acontplus.Core - Core abstractions and patterns
🤝 Contributing
We welcome contributions! Please see our Contributing Guidelines for details.
Development Setup
git clone https://github.com/Acontplus-S-A-S/acontplus-dotnet-libs.git
cd acontplus-dotnet-libs
dotnet restore
dotnet build
📄 License
This project is licensed under the MIT License - see the LICENSE file for details.
🆘 Support
- 📧 Email: proyectos@acontplus.com
- 🐛 Issues: GitHub Issues
- 📖 Documentation: Wiki
👨💻 Author
Ivan Paz - @iferpaz7
🏢 Company
Acontplus S.A.S. - Enterprise software solutions
Built with ❤️ for the .NET community using cutting-edge .NET 9 features
Product | Versions 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. |
-
net9.0
- Acontplus.Core (>= 1.4.3)
- Microsoft.EntityFrameworkCore (>= 9.0.8)
- Microsoft.Extensions.Configuration.Abstractions (>= 9.0.8)
- Microsoft.Extensions.DependencyInjection (>= 9.0.8)
- Microsoft.Extensions.DependencyInjection.Abstractions (>= 9.0.8)
- Microsoft.Extensions.Logging.Abstractions (>= 9.0.8)
NuGet packages (2)
Showing the top 2 NuGet packages that depend on Acontplus.Persistence.Common:
Package | Downloads |
---|---|
Acontplus.Persistence.SqlServer
Advanced library for SQL Server persistence with Entity Framework Core integration. Includes repositories, context management, ADO.NET support, advanced error handling, and enterprise-ready data access patterns for SQL Server databases. |
|
Acontplus.Persistence.Postgres
Advanced library for PostgreSQL persistence with Entity Framework Core integration. Includes repositories, context management, ADO.NET support, advanced error handling, and enterprise-ready data access patterns for PostgreSQL databases. |
GitHub repositories
This package is not used by any popular GitHub repositories.
Enhanced with contemporary repository patterns, multi-provider support, connection string management, context factory patterns, and enterprise-ready abstractions for SQL Server, PostgreSQL, and other database providers.