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
                    
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="Acontplus.Persistence.Common" Version="1.1.3" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Acontplus.Persistence.Common" Version="1.1.3" />
                    
Directory.Packages.props
<PackageReference Include="Acontplus.Persistence.Common" />
                    
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 Acontplus.Persistence.Common --version 1.1.3
                    
#r "nuget: Acontplus.Persistence.Common, 1.1.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 Acontplus.Persistence.Common@1.1.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=Acontplus.Persistence.Common&version=1.1.3
                    
Install as a Cake Addin
#tool nuget:?package=Acontplus.Persistence.Common&version=1.1.3
                    
Install as a Cake Tool

Acontplus.Persistence.Common

NuGet .NET License

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 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 (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.

Version Downloads Last Updated
1.1.3 0 8/8/2025
1.1.2 37 8/7/2025
1.1.1 39 8/7/2025
1.1.0 40 8/7/2025
1.0.3 44 8/5/2025
1.0.2 42 8/5/2025
1.0.1 484 7/23/2025
1.0.0 485 7/23/2025

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.