Back to list
islamu-ngo

dotnet-efcore-guidelines

by islamu-ngo

Event Platform & Management System in development.

5🍴 1📅 Jan 19, 2026

SKILL.md


name: dotnet-efcore-guidelines description: Entity Framework Core best practices for Clean Architecture projects. Covers DbContext, entity configurations, repository pattern, migrations, and PostgreSQL-specific features. type: domain enforcement: suggest priority: high

.NET + Entity Framework Core Guidelines

Project-Agnostic EF Core Patterns

Placeholders use {Placeholder} syntax - see docs/TEMPLATE_GLOSSARY.md.

Purpose

This skill provides comprehensive best practices for using Entity Framework Core with PostgreSQL in Clean Architecture projects. It details conventions for DbContext, entity configurations, repository patterns, migrations, and PostgreSQL-specific features.

When This Skill Activates

Triggered by:

  • Keywords: "ef core", "entity framework", "dbcontext", "repository", "migration", "database", "postgres", "postgresql"
  • File patterns: **/Persistence/**/*.cs, **/Repositories/**/*.cs, **/*DbContext.cs, **/Configurations/**/*.cs

EF Core Architecture

The persistence layer ({Project}.Persistence) is responsible for data access and storage. It implements interfaces defined in the Application layer, adhering to Clean Architecture principles.

graph TD
    subgraph Application Layer
        A[I{Entity}Repository] --> B[{Entity}]
        B[{Entity}] --> C[Domain Layer]
    end

    subgraph Persistence Layer
        D[{DbContext}] --> B
        E[{Entity}Repository] --> D
        E --> A
    end

    A -- Implemented by --> E
    C -- Used by --> B
    D -- Configures --> B

Resources

For more detailed examples, refer to the resources/ folder within this skill.

ResourceDescription
dbcontext-patterns.mdDbContext configuration, SaveChangesAsync override
entity-configuration.mdIEntityTypeConfiguration, TPT, PostgreSQL functions
repository-pattern.mdGenericRepository, custom repositories
querying-patterns.mdInclude, Select, projections, performance
migrations.mdCreating and applying migrations

Quick Reference

1. DbContext Pattern

The {DbContext} manages database interactions.

// File: {Project}.Persistence/{DbContext}.cs
public class {DbContext} : DbContext
{
    public {DbContext}(DbContextOptions<{DbContext}> options) : base(options) { }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        // Automatically applies all IEntityTypeConfiguration<T> from the assembly
        modelBuilder.ApplyConfigurationsFromAssembly(typeof({DbContext}).Assembly);
    }

    // Override SaveChangesAsync for cross-cutting concerns like auditing or soft deletes
    public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        // Example: Audit logging or automatic timestamp updates
        foreach (var entry in ChangeTracker.Entries())
        {
            // Handle CreatedAt, UpdatedAt logic
        }
        return base.SaveChangesAsync(cancellationToken);
    }

    public DbSet<{Entity}> {Entities} { get; set; } = null!;
    public DbSet<{ParentEntity}> {ParentEntities} { get; set; } = null!;
    // ... other DbSets
}

For more details, see dbcontext-patterns.md.

2. Entity Configuration

All entity-specific configurations are done using IEntityTypeConfiguration<T> in separate classes.

// File: {Project}.Persistence/Configurations/Entities/{Entity}Configuration.cs
public class {Entity}Configuration : IEntityTypeConfiguration<{Entity}>
{
    public void Configure(EntityTypeBuilder<{Entity}> builder)
    {
        // Project Standard: Table Per Type (TPT) inheritance strategy
        builder.UseTptMappingStrategy();

        // Project Standard: UUIDv7 primary keys for main entities
        builder.Property(e => e.Id).HasDefaultValueSql("uuidv7()");

        // Database-level defaults are acceptable here, not in domain entities
        builder.Property(e => e.ViewCount).HasDefaultValue(0);

        builder.Property(e => e.Title).HasMaxLength(200).IsRequired();
        builder.Property(e => e.Description).HasMaxLength(5000);

        // Example relationship configuration
        builder.HasOne(e => e.{ParentEntity})
            .WithMany()
            .HasForeignKey(e => e.{ParentEntity}Id)
            .OnDelete(DeleteBehavior.Restrict);
    }
}

For more details, see entity-configuration.md.

3. Repository Pattern

Repositories abstract data access. Interfaces reside in the Application layer, and implementations are in the Persistence layer.

CRITICAL RULE: Repositories MUST return DOMAIN ENTITIES, not DTOs. DTO mapping always happens in the Application layer handlers via AutoMapper.

// File: {Project}.Application/Contracts/Persistence/I{Entity}Repository.cs (Application Layer)
public interface I{Entity}Repository : IGenericRepository<{Entity}, {IdType}>
{
    Task<List<{Entity}>> Get{Entities}WithDetails(); // Returns List<{Entity}>
    Task<{Entity}?> Get{Entity}WithDetails({IdType} id); // Returns {Entity}?
}

// File: {Project}.Persistence/Repositories/{Entity}Repository.cs (Persistence Layer)
public class {Entity}Repository : GenericRepository<{Entity}, {IdType}>, I{Entity}Repository
{
    private readonly {DbContext} _dbContext;

    public {Entity}Repository({DbContext} dbContext) : base(dbContext) => _dbContext = dbContext;

    public async Task<List<{Entity}>> Get{Entities}WithDetails()
    {
        return await _dbContext.{Entities}
            .Include(e => e.{LookupEntity})
            .Include(e => e.{RelatedEntity1})
            .Include(e => e.{RelatedEntity2})
            .ToListAsync(); // Returns entities
    }
}

For more details, see repository-pattern.md.

4. Querying Patterns

Efficient querying is crucial for performance. Avoid N+1 issues by using eager loading (Include) and projections (Select).

// Example: Query with eager loading and projection to DTO (in Application Layer Handler)
public async Task<List<{Entity}ListDto>> Handle(Get{Entity}ListRequest request, CancellationToken cancellationToken)
{
    var {entities} = await _{entity}Repository.Get{Entities}WithDetails(); // Repository returns entities
    return _mapper.Map<List<{Entity}ListDto>>({entities}); // Handler maps to DTOs
}

// Example: Using AsNoTracking for read-only queries (in Repository)
public async Task<List<{Entity}>> Get{Entities}ReadOnly()
{
    return await _dbContext.{Entities}
        .AsNoTracking() // Disables change tracking for performance
        .Include(e => e.{ParentEntity})
        .ToListAsync();
}

For more details, see querying-patterns.md.

5. Migrations

Database schema changes are managed through EF Core migrations.

# Create a new migration for schema changes
dotnet ef migrations add AddNewFieldTo{Entity} --project {Project}.Persistence

# Apply pending migrations to the database
dotnet ef database update --project {Project}.Persistence

# Generate SQL script for production deployment
dotnet ef migrations script --idempotent --output migrations/release.sql --project {Project}.Persistence

For more details, see migrations.md.

Key Principles & Conventions

  • IDs: All primary keys are Guid (or {IdType}), except for lookup tables which use int (or {LookupIdType}).
  • Numeric Types: Use int instead of long unless explicitly required for large values (e.g., file sizes, pagination cursors).
  • Default Values: DO NOT add default values in domain entity property initializers (e.g., public int ViewCount { get; set; } = 0;). Set defaults in application handlers or use database-level defaults via IEntityTypeConfiguration.
  • Link Tables: Navigation properties on link/mapping tables are readonly for queries only. Writes must go through the link table's repository directly.
  • PostgreSQL Features: Leverage PostgreSQL-specific features like UUIDv7 for primary keys and PostGIS for spatial data handling.

Related Documentation:

Score

Total Score

65/100

Based on repository quality metrics

SKILL.md

SKILL.mdファイルが含まれている

+20
LICENSE

ライセンスが設定されている

+10
説明文

100文字以上の説明がある

0/10
人気

GitHub Stars 100以上

0/15
最近の活動

1ヶ月以内に更新

+10
フォーク

10回以上フォークされている

0/5
Issue管理

オープンIssueが50未満

+5
言語

プログラミング言語が設定されている

+5
タグ

1つ以上のタグが設定されている

+5

Reviews

💬

Reviews coming soon