A3.Backend.Persistence 4.1.0

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

A3.Backend.Persistence

Librería NuGet para acceso a base de datos MySQL del sistema Genie (A3), implementando los patrones Repository y Unit of Work sobre Entity Framework Core 8.


Tabla de contenidos


Requisitos

Dependencia Versión
.NET 8.0
Microsoft.EntityFrameworkCore.Tools 8.0.5
MySql.EntityFrameworkCore 8.0.5
Newtonsoft.Json 13.0.3

Instalación

dotnet add package A3.Backend.Persistence

Arquitectura

El proyecto expone 6 contextos independientes, cada uno con su propio stack de Repository + UnitOfWork + Factory.

A3.Backend.Persistence
├── Context/
│   ├── Admin/          → GenieAdminContext
│   ├── Operations/     → GenieOperationsContext
│   ├── Templates/      → GenieTemplatesContext
│   ├── DBManager/      → GenieDBManagerContext
│   ├── Registry/       → RegistryContext
│   └── TrxFraud/       → GenieBackendTrxFraudReviewContext
│
├── Models/             → Entidades EF por contexto
│
├── Repository/
│   ├── IUnitOfWorkFactory<TUnitOfWork>
│   ├── Admin/          → IAdminRepository, IAdminUnitOfWork, AdminUnitOfWorkFactory
│   ├── Operations/     → IOperationsRepository, IOperationsUnitOfWork, OperationsUnitOfWorkFactory
│   ├── Templates/      → ITemplatesRepository, ITemplatesUnitOfWork, TemplatesUnitOfWorkFactory
│   ├── DBManager/      → IDbManagerRepository, IDbManagerUnitOfWork, DbManagerUnitOfWorkFactory
│   ├── Registry/       → IRegistryRepository, IRegistryUnitOfWork, RegistryUnitOfWorkFactory
│   └── TrxFraud/       → ITrxFraudRepository, ITrxFraudUnitOfWork, TrxFraudUnitOfWorkFactory
│
└── Utils/
    └── Utils.cs        → DiffDates(DateTime, DateTime)

Tipos de conexión por contexto

Contexto Tipo de conexión Factory
Admin DbContextOptions (estática) AdminUnitOfWorkFactory
DBManager DbContextOptions (estática) DbManagerUnitOfWorkFactory
Registry DbContextOptions (estática) RegistryUnitOfWorkFactory
TrxFraud DbContextOptions (estática) TrxFraudUnitOfWorkFactory
Operations string dinámica OperationsUnitOfWorkFactory
Templates string dinámica TemplatesUnitOfWorkFactory

Operations y Templates aceptan una connection string en runtime, lo que permite soporte multi-tenant (una BD por cliente).


Contextos de base de datos

Contexto Responsabilidad
GenieAdminContext Usuarios, roles, permisos, subproyectos, configuración, catálogos geográficos, dispositivos
GenieOperationsContext Transacciones, invitaciones, personas, enrollments, logs, OTPs, imágenes
GenieTemplatesContext Datos biométricos (templates)
GenieDBManagerContext APIs autorizadas, gestión de bases de datos
RegistryContext Logs de ejecución del registro
GenieBackendTrxFraudReviewContext Revisión de fraude en transacciones

Registro en DI

Contextos estáticos (Admin, DBManager, Registry, TrxFraud)

using A3.Backend.Persistence.Context.Admin;
using A3.Backend.Persistence.Repository;
using A3.Backend.Persistence.Repository.Admin;
using Microsoft.EntityFrameworkCore;

// Registrar UnitOfWork como Scoped para uso normal
services.AddScoped<IAdminUnitOfWork>(sp =>
{
    var optionsBuilder = new DbContextOptionsBuilder<GenieAdminContext>();
    optionsBuilder.UseMySQL(configuration.GetConnectionString("AdminConnection"));
    return new AdminUnitOfWork(new GenieAdminContext(optionsBuilder.Options));
});

// Registrar Factory como Singleton para uso paralelo
services.AddSingleton<IUnitOfWorkFactory<IAdminUnitOfWork>>(sp =>
{
    var optionsBuilder = new DbContextOptionsBuilder<GenieAdminContext>();
    optionsBuilder.UseMySQL(configuration.GetConnectionString("AdminConnection"));
    return new AdminUnitOfWorkFactory(optionsBuilder.Options);
});

Contextos dinámicos (Operations, Templates)

using A3.Backend.Persistence.Repository.Operations;

// Factory que recibe la connection string en runtime
services.AddTransient<Func<string, IOperationsUnitOfWork>>(sp =>
    connectionString => new OperationsUnitOfWork(connectionString));

Uso básico

public class UserService
{
    private readonly IAdminUnitOfWork _uow;

    public UserService(IAdminUnitOfWork uow) => _uow = uow;

    public User? GetById(int id)
        => _uow.Repository<User>().Get(id);

    public IEnumerable<User> GetActive()
        => _uow.Repository<User>().Find(u => u.Active == true);

    public void Create(User user)
    {
        _uow.Repository<User>().Add(user);
        _uow.Save();
    }

    public async Task<int> UpdateEmailAsync(int id, string email)
        => _uow.Repository<User>().UpdateRange(
            u => u.Id == id,
            s => s.SetProperty(u => u.Email, email));
}

Conexiones dinámicas (multi-tenant)

Para Operations y Templates, la connection string se resuelve en runtime por cliente/tenant:

public class TransactionService
{
    private readonly Func<string, IOperationsUnitOfWork> _uowFactory;

    public TransactionService(Func<string, IOperationsUnitOfWork> uowFactory)
        => _uowFactory = uowFactory;

    public Transaction? GetTransaction(string tenantConnectionString, int id)
    {
        using var uow = _uowFactory(tenantConnectionString);
        return uow.Repository<Transaction>().Get(id);
    }
}

O directamente con la factory:

var factory = new OperationsUnitOfWorkFactory(tenantConnectionString);
using var uow = factory.Create();
var transactions = uow.Repository<Transaction>().GetAll();

Consultas paralelas

⚠️ DbContext no es thread-safe. Para consultas paralelas siempre usar la Factory para crear un contexto por hilo.

Contextos estáticos

public async Task<List<User>> GetUsersParallelAsync(
    IUnitOfWorkFactory<IAdminUnitOfWork> factory,
    List<int> ids)
{
    var tasks = ids.Select(id => Task.Run(() =>
    {
        using var uow = factory.Create();
        return uow.Repository<User>().Get(id);
    }));

    return (await Task.WhenAll(tasks)).Where(u => u != null).ToList()!;
}

Contextos dinámicos (multi-tenant en paralelo)

public async Task<Dictionary<string, List<Transaction>>> GetAllTenantsAsync(
    Dictionary<string, string> tenantConnections)
{
    var tasks = tenantConnections.Select(async kvp =>
    {
        var factory = new OperationsUnitOfWorkFactory(kvp.Value);
        using var uow = factory.Create();
        var data = uow.Repository<Transaction>().GetAll().ToList();
        return new { Tenant = kvp.Key, Data = data };
    });

    var results = await Task.WhenAll(tasks);
    return results.ToDictionary(r => r.Tenant, r => r.Data);
}

Consultas mixtas (Admin + Operations en paralelo)

public async Task<(User user, List<Transaction> transactions)> GetReportAsync(
    IUnitOfWorkFactory<IAdminUnitOfWork> adminFactory,
    string operationsConnStr,
    int userId)
{
    var userTask = Task.Run(() =>
    {
        using var uow = adminFactory.Create();
        return uow.Repository<User>().Get(userId);
    });

    var trxTask = Task.Run(() =>
    {
        var factory = new OperationsUnitOfWorkFactory(operationsConnStr);
        using var uow = factory.Create();
        return uow.Repository<Transaction>().Find(t => t.UserId == userId).ToList();
    });

    await Task.WhenAll(userTask, trxTask);
    return (await userTask, await trxTask);
}

Referencia de la interfaz Repository

Todos los repositorios exponen los mismos métodos base:

Método Descripción
GetAll() Retorna todas las entidades
Get(int id) Busca por clave primaria entera
Get(string name) Busca por propiedad Name
Find(predicate) Filtra con expresión lambda
Find(predicate, includes) Filtra con includes de navegación
Add(entity) Agrega una entidad
AddRange(entities) Agrega una lista de entidades
Update(entity) Marca la entidad como modificada
UpdateRange(predicate, setPropertyCalls) Actualización masiva con EF ExecuteUpdate
Delete(int id) Elimina por id
Delete(predicate) Eliminación masiva con EF ExecuteDelete
Save() Persiste los cambios en la BD
FromSqlRaw(params, sql) Ejecuta un stored procedure o SQL raw

Métodos específicos por contexto

Admin

Método Descripción
JoinGetAssingTech(subCustomerId) Técnico asignado con menor carga
JoinGetScores(subCustomer) Scores activos de un subproyecto
JoinGetScoreById(subprojectId, scoreId) Score específico
JoinGetTransactionsPending(idUser?) Transacciones pendientes de revisión
JoinGetTransactionsByTech() Transacciones agrupadas por técnico

Operations

Método Descripción
JoinGetHistoricSoreById(idTransaction) Historial de scores de una transacción
JoinGetHistoricSoreRejectedById(idTransaction) Historial de scores rechazados
JoinGePersontData(personId, subCustomerId, name) Datos completos de una persona
JoinGetTransactionsByTechOp(trxOrigin, subCustomerId, date) Transacciones por técnico en Operations

Modelos por contexto

<details> <summary><strong>Admin</strong></summary>

User · UserRole · UserBySubcustomer · UserPasswordHistory · UserBlocked · UserSeed · UsersAttribute · LogUserBlocking · Token · ProjectUserActive · RolesBySubCustomer · ModuleRole · SubModuleRole · Module · SubModule · Endpoint · EndpointsByModule · EndpointsBySubModule · Customer · SubProject · Branch · Place · Address · Location · ConfigurationParameter · SubCustomerConfiguration · LockConfiguration · LockoutPeriod · Country · CountriesNew · City · CitiesNew · StatesNew · NumericalCodeCountry · TechnicianBySubProject · AssingTechnician · TransactionPendigReview · Template · TemplateType · IdentificationType · IdentificationTypeBySubproject · CausalRejection · RiskLevel · Permutation · Step · SubStep · PushDataField · PushDataFieldBySubCustomer · ResultDataField · ResultDataFieldBySubCustomer · LookAndFeelFile · TransactionType · TransactionScore · TransactionScoresBySubproject · Device · Middle · AuthorizedPhone · StatePerson · TransactionState · ScoreScript · ScriptGroup

</details>

<details> <summary><strong>Operations</strong></summary>

Invitation · InvitationDevice · InvitationPerson · InvitationStep · InvitationStepConfig · InvitationTemplate · Person · Enrollment · EnrollmentTemplate · Transaction · TransactionImage · TransactionProperty · TransactionReviewScore · Log · LogEvent · LogImage · ServiceLog · ErrorLog · ExecutionsLog · ApplicationAlert · ApplicationAudit · Otp · PendingAction · HistoricQualification · IdentitiesBySubProject · ResponseControlList · ResponseImage · ReviewExtractDataV2 · ReviewRegula · TemporalData · VwInfoTransaction

</details>

<details> <summary><strong>Templates</strong></summary>

BiometricData

</details>

<details> <summary><strong>DBManager</strong></summary>

AuthorizedApi · Database

</details>

<details> <summary><strong>Registry</strong></summary>

ErrorLog · ExecutionLog

</details>

<details> <summary><strong>TrxFraud</strong></summary>

Transaction · DeviceFingerprint · RiskThreshold · ErrorLog

</details>


Configuración MySQL recomendada

{
  "ConnectionStrings": {
    "AdminConnection":      "server=host;database=admin_db;user=usr;password=***;Max Pool Size=100;",
    "OperationsConnection": "server=host;database=ops_db;user=usr;password=***;Max Pool Size=50;",
    "TemplatesConnection":  "server=host;database=tpl_db;user=usr;password=***;Max Pool Size=50;"
  }
}

Licencia

Consulta el archivo LICENSE.txt para más información.

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
4.1.0 32 2/27/2026
4.0.0 28 2/27/2026
3.2.50.1 100 1/27/2026
3.2.50 98 1/27/2026
3.2.49.2 99 1/13/2026
3.2.49.1 103 1/7/2026
3.2.49 96 1/7/2026
3.2.48.44 78 2/25/2026
3.2.48.43 125 2/19/2026
3.2.48.42 169 2/4/2026
3.2.48.41 151 1/20/2026
3.2.48.40 99 1/14/2026
3.2.48.39 103 1/8/2026
3.2.48.38 105 1/8/2026
3.2.48.37 100 1/8/2026
3.2.48.36 190 12/12/2025
3.2.48.35 166 11/28/2025
3.2.48.34 197 11/27/2025
3.2.48.33 259 11/24/2025
3.2.48.32 308 11/12/2025
Loading failed