Przejdź do treści

TailoredApps.Shared.EntityFramework

NuGet License: MIT


Opis

Biblioteka dostarcza kompletną implementację wzorca Unit of Work na bazie Entity Framework Core. Rozwiązuje problem niekontrolowanego zarządzania transakcjami w aplikacjach wielowarstwowych — zamiast bezpośrednio wywoływać SaveChanges() w każdym repozytorium, masz jeden punkt kontroli (IUnitOfWork), który zarządza cyklem życia transakcji.

Kluczowe możliwości: - Transakcje z konfigurowalnymi poziomami izolacji - Auditing — automatyczne śledzenie zmian encji (kto i co zmienił) - HooksIHook do wykonywania kodu przed/po SaveChanges lub commit/rollback transakcji - Obsługa InMemory provider na potrzeby testów


Instalacja

dotnet add package TailoredApps.Shared.EntityFramework

Rejestracja w DI

// Program.cs
using TailoredApps.Shared.EntityFramework;

// Podstawowa rejestracja
builder.Services.AddUnitOfWork<IApplicationDbContext, ApplicationDbContext>()
    .WithAudit<AuditContext>(options =>
    {
        options.IgnoreProperty("RowVersion");
    });

Gdzie IApplicationDbContext to interfejs Twojego DbContext, a ApplicationDbContext — implementacja dziedzicząca po DbContext.


Przykład użycia

Definicja kontekstu

public interface IApplicationDbContext
{
    DbSet<Order> Orders { get; }
    DbSet<Customer> Customers { get; }
}

public class ApplicationDbContext : DbContext, IApplicationDbContext
{
    public DbSet<Order> Orders { get; set; }
    public DbSet<Customer> Customers { get; set; }

    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
        : base(options) { }
}

Użycie w serwisie

public class OrderService
{
    private readonly IUnitOfWork<IApplicationDbContext> _uow;

    public OrderService(IUnitOfWork<IApplicationDbContext> uow)
    {
        _uow = uow;
    }

    public async Task<Order> CreateOrderAsync(CreateOrderRequest request)
    {
        var order = new Order
        {
            CustomerId = request.CustomerId,
            TotalAmount = request.TotalAmount,
            Status = OrderStatus.Pending
        };

        _uow.DataProvider.Orders.Add(order);
        await _uow.SaveChangesAsync();

        return order;
    }

    public async Task TransferFundsAsync(int fromId, int toId, decimal amount)
    {
        // Ręczna kontrola transakcji z poziomem izolacji
        _uow.SetIsolationLevel(System.Data.IsolationLevel.Serializable);

        try
        {
            var from = await _uow.DataProvider.Accounts.FindAsync(fromId);
            var to = await _uow.DataProvider.Accounts.FindAsync(toId);

            from.Balance -= amount;
            to.Balance += amount;

            await _uow.SaveChangesAsync();
            _uow.CommitTransaction();
        }
        catch
        {
            _uow.RollbackTransaction();
            throw;
        }
    }
}

Hook — przykład logowania po zapisie

public class AuditLogHook : IHook
{
    private readonly ILogger<AuditLogHook> _logger;

    public AuditLogHook(ILogger<AuditLogHook> logger) => _logger = logger;

    public Task PostSaveChangesAsync(IEnumerable<EntityChange> changes, CancellationToken ct)
    {
        foreach (var change in changes)
            _logger.LogInformation("Entity {Type} {Id}: {State}", 
                change.EntityType, change.EntityId, change.State);
        return Task.CompletedTask;
    }
}

API Reference

Typ Rodzaj Opis
IUnitOfWork Interfejs Zarządzanie transakcją: SaveChanges, CommitTransaction, RollbackTransaction
IUnitOfWork<T> Interfejs Rozszerza IUnitOfWork o DataProvider (dostęp do DbContext)
IUnitOfWorkContext Interfejs Niskopoziomowe operacje: BeginTransaction, SaveChanges, DiscardChanges
UnitOfWorkContext<T> Klasa Implementacja EF Core IUnitOfWorkContext
ITransaction Interfejs Transakcja: Commit(), Rollback(), Dispose()
IHook Interfejs Marker interface dla hooków cyklu życia UoW
IHooksManager Interfejs Zarządza kolekcją hooków i ich wykonywaniem
IAuditSettings Interfejs Konfiguracja audytingu (ignorowane właściwości itp.)
IEntityChangesAuditor Interfejs Zbiera i zapisuje zmiany encji
EntityChange Klasa Opis zmiany: typ encji, ID, stary/nowy stan
AuditEntityState Enum Added, Modified, Deleted

🤖 AI Agent Prompt

## TailoredApps.Shared.EntityFramework — Instrukcja dla agenta AI

Używasz biblioteki TailoredApps.Shared.EntityFramework (Unit of Work pattern na EF Core).

### Rejestracja
```csharp
builder.Services.AddUnitOfWork<IMyDbContext, MyDbContext>();

Użycie

// Wstrzyknij IUnitOfWork<IMyDbContext>
_uow.DataProvider.Orders.Add(order);
await _uow.SaveChangesAsync();

// Transakcja manualna
_uow.SetIsolationLevel(IsolationLevel.ReadCommitted);
try {
    // operacje...
    await _uow.SaveChangesAsync();
    _uow.CommitTransaction();
} catch {
    _uow.RollbackTransaction();
    throw;
}

Zasady

  • Nigdy nie wywołuj DbContext.SaveChanges() bezpośrednio — używaj _uow.SaveChangesAsync()
  • Domyślnie transakcja jest otwierana przy pierwszym SaveChanges i commitowana automatycznie przez TransactionFilter (jeśli używasz WebApiCore)
  • Dla testów: użyj InMemory provider — UnitOfWorkContext automatycznie to obsługuje
  • HasOpenTransaction sprawdza, czy jest otwarta transakcja ```