skills/stuartf303/sorcha/entity-framework

entity-framework

SKILL.md

Entity Framework Core Skill

Sorcha uses EF Core 9+ with PostgreSQL (Npgsql) as the primary relational data store. The codebase implements a layered repository pattern with generic and specialized repositories, soft delete via query filters, and automatic migrations on startup.

Quick Start

Register DbContext with PostgreSQL

// src/Common/Sorcha.Storage.EFCore/Extensions/EFCoreServiceExtensions.cs
services.AddDbContext<WalletDbContext>((sp, options) =>
{
    var dataSource = sp.GetRequiredService<NpgsqlDataSource>();
    options.UseNpgsql(dataSource, npgsql =>
    {
        npgsql.EnableRetryOnFailure(maxRetryCount: 10, maxRetryDelay: TimeSpan.FromSeconds(30), errorCodesToAdd: null);
        npgsql.MigrationsHistoryTable("__EFMigrationsHistory", "wallet");
    });
});

Create a Migration

# From project directory containing DbContext
dotnet ef migrations add InitialSchema --project src/Common/Sorcha.Wallet.Core --startup-project src/Services/Sorcha.Wallet.Service

Apply Migrations Programmatically

// Startup pattern used in Sorcha services
var pending = await dbContext.Database.GetPendingMigrationsAsync();
if (pending.Any())
    await dbContext.Database.MigrateAsync();

Key Concepts

Concept Usage Example
DbContext Schema definition + change tracking WalletDbContext, TenantDbContext
Repository Data access abstraction EFCoreRepository<T, TId, TContext>
Soft Delete Query filter on DeletedAt .HasQueryFilter(e => e.DeletedAt == null)
JSONB PostgreSQL JSON columns .HasColumnType("jsonb")
ExecuteUpdate Bulk updates without loading ExecuteUpdateAsync(s => s.SetProperty(...))

Common Patterns

Repository with Optional Eager Loading

// src/Common/Sorcha.Wallet.Core/Repositories/EfCoreWalletRepository.cs
public async Task<WalletEntity?> GetByAddressAsync(string address, bool includeAddresses = false)
{
    IQueryable<WalletEntity> query = _context.Wallets;
    
    if (includeAddresses)
        query = query.Include(w => w.Addresses);
    
    return await query.AsNoTracking().FirstOrDefaultAsync(w => w.Address == address);
}

Soft Delete with Filter Bypass

// Bypass query filter for admin operations
var deleted = await _context.Wallets
    .IgnoreQueryFilters()
    .FirstOrDefaultAsync(w => w.Address == address);

See Also

  • patterns - DbContext configuration, entity mapping, query optimization
  • workflows - Migration commands, testing patterns, deployment

Related Skills

  • See the postgresql skill for connection configuration and PostgreSQL-specific features
  • See the aspire skill for service registration and health checks
  • See the xunit skill for testing DbContext with InMemory provider

Documentation Resources

Fetch latest EF Core documentation with Context7.

Library ID: /dotnet/entityframework.docs

Recommended Queries:

  • "DbContext pooling configuration dependency injection"
  • "migrations code-first apply production deployment"
  • "query filters soft delete global filters"
  • "bulk operations ExecuteUpdate ExecuteDelete"
Weekly Installs
37
First Seen
Jan 27, 2026
Installed on
opencode35
gemini-cli35
github-copilot34
amp34
codex34
kimi-cli34