Skip to main content
ClaudeWave
Skill64 repo starsupdated 22d ago

dotnet-repository-pattern

Generates Repository interfaces and implementations following the Repository pattern. Provides data access abstraction for aggregate roots with EF Core implementations.

Install in Claude Code
Copy
git clone --depth 1 https://github.com/ronnythedev/dotnet-clean-architecture-skills /tmp/dotnet-repository-pattern && cp -r /tmp/dotnet-repository-pattern/skills/05-dotnet-repository-pattern ~/.claude/skills/dotnet-repository-pattern
Then start a new Claude Code session; the skill loads automatically.

SKILL.md

# Repository Pattern Generator

## Overview

This skill generates Repositories that provide an abstraction over data access:

- **Interface in Domain layer** - Defines data access contract
- **Implementation in Infrastructure** - Uses EF Core
- **Per Aggregate Root** - Not per entity
- **Unit of Work integration** - SaveChanges via IUnitOfWork

## Quick Reference

| Repository Method | Purpose | Returns |
|-------------------|---------|---------|
| `GetByIdAsync` | Retrieve by primary key | `Entity?` |
| `GetByXxxAsync` | Retrieve by business key | `Entity?` |
| `GetAllAsync` | Retrieve all (use sparingly) | `IReadOnlyList<Entity>` |
| `Add` | Track new entity | `void` |
| `Update` | Track modified entity | `void` |
| `Remove` | Track deleted entity | `void` |
| `ExistsAsync` | Check existence | `bool` |

---

## Repository Structure

```
/Domain/{Aggregate}/
└── I{Entity}Repository.cs          # Interface (Domain layer)

/Infrastructure/Repositories/
└── {Entity}Repository.cs           # Implementation (Infrastructure layer)
```

---

## Template: Repository Interface (Domain Layer)

```csharp
// src/{name}.domain/{Aggregate}/I{Entity}Repository.cs
namespace {name}.domain.{aggregate};

public interface I{Entity}Repository
{
    // ═══════════════════════════════════════════════════════════════
    // QUERY METHODS
    // ═══════════════════════════════════════════════════════════════
    
    /// <summary>
    /// Gets an entity by its unique identifier
    /// </summary>
    Task<{Entity}?> GetByIdAsync(
        Guid id,
        CancellationToken cancellationToken = default);

    /// <summary>
    /// Gets an entity by its unique identifier with related entities
    /// </summary>
    Task<{Entity}?> GetByIdWithDetailsAsync(
        Guid id,
        CancellationToken cancellationToken = default);

    /// <summary>
    /// Gets an entity by a unique business key
    /// </summary>
    Task<{Entity}?> GetByNameAsync(
        string name,
        CancellationToken cancellationToken = default);

    /// <summary>
    /// Gets all entities for a parent organization
    /// </summary>
    Task<IReadOnlyList<{Entity}>> GetByOrganizationIdAsync(
        Guid organizationId,
        CancellationToken cancellationToken = default);

    /// <summary>
    /// Gets all active entities
    /// </summary>
    Task<IReadOnlyList<{Entity}>> GetAllActiveAsync(
        CancellationToken cancellationToken = default);

    /// <summary>
    /// Checks if an entity exists
    /// </summary>
    Task<bool> ExistsAsync(
        Guid id,
        CancellationToken cancellationToken = default);

    /// <summary>
    /// Checks if an entity with the given name exists
    /// </summary>
    Task<bool> ExistsByNameAsync(
        string name,
        CancellationToken cancellationToken = default);

    // ═══════════════════════════════════════════════════════════════
    // COMMAND METHODS (tracking only, no SaveChanges)
    // ═══════════════════════════════════════════════════════════════
    
    /// <summary>
    /// Adds a new entity to the context
    /// </summary>
    void Add({Entity} {entity});

    /// <summary>
    /// Adds multiple entities to the context
    /// </summary>
    void AddRange(IEnumerable<{Entity}> {entities});

    /// <summary>
    /// Updates an existing entity in the context
    /// </summary>
    void Update({Entity} {entity});

    /// <summary>
    /// Removes an entity from the context
    /// </summary>
    void Remove({Entity} {entity});

    /// <summary>
    /// Removes multiple entities from the context
    /// </summary>
    void RemoveRange(IEnumerable<{Entity}> {entities});
}
```

---

## Template: Repository Implementation (Infrastructure Layer)

```csharp
// src/{name}.infrastructure/Repositories/{Entity}Repository.cs
using Microsoft.EntityFrameworkCore;
using {name}.domain.{aggregate};

namespace {name}.infrastructure.repositories;

internal sealed class {Entity}Repository : I{Entity}Repository
{
    private readonly ApplicationDbContext _dbContext;

    public {Entity}Repository(ApplicationDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    // ═══════════════════════════════════════════════════════════════
    // QUERY METHODS
    // ═══════════════════════════════════════════════════════════════

    public async Task<{Entity}?> GetByIdAsync(
        Guid id,
        CancellationToken cancellationToken = default)
    {
        return await _dbContext
            .Set<{Entity}>()
            .FirstOrDefaultAsync(e => e.Id == id, cancellationToken);
    }

    public async Task<{Entity}?> GetByIdWithDetailsAsync(
        Guid id,
        CancellationToken cancellationToken = default)
    {
        return await _dbContext
            .Set<{Entity}>()
            .Include(e => e.{ChildEntities})
            .Include(e => e.{OtherRelation})
            .FirstOrDefaultAsync(e => e.Id == id, cancellationToken);
    }

    public async Task<{Entity}?> GetByNameAsync(
        string name,
        CancellationToken cancellationToken = default)
    {
        return await _dbContext
            .Set<{Entity}>()
            .FirstOrDefaultAsync(
                e => e.Name.ToLower() == name.ToLower(),
                cancellationToken);
    }

    public async Task<IReadOnlyList<{Entity}>> GetByOrganizationIdAsync(
        Guid organizationId,
        CancellationToken cancellationToken = default)
    {
        return await _dbContext
            .Set<{Entity}>()
            .Where(e => e.OrganizationId == organizationId)
            .OrderBy(e => e.Name)
            .ToListAsync(cancellationToken);
    }

    public async Task<IReadOnlyList<{Entity}>> GetAllActiveAsync(
        CancellationToken cancellationToken = default)
    {
        return await _dbContext
            .Set<{Entity}>()
            .Where(e => e.IsActive)
            .OrderBy(e => e.Name)
            .ToListAsync(cancellationToken);
    }

    public async Task<bool> ExistsAsync(
dotnet-clean-architectureSkill

Scaffolds a complete .NET solution following Clean Architecture principles with proper layer separation (API, Application, Domain, Infrastructure). Creates project structure, dependency injection setup, and cross-cutting concerns configuration.

dotnet-cqrs-command-generatorSkill

Generates CQRS Commands with Handlers, Validators, and Request DTOs following Clean Architecture patterns. Commands represent actions that modify state and return Result types for proper error handling.

dotnet-cqrs-query-generatorSkill

Generates CQRS Queries with Handlers and Response DTOs for read operations. Uses Dapper for optimized read queries, bypassing the domain model for better performance.

dotnet-domain-entity-generatorSkill

Generates Domain Entities following DDD principles with factory methods, private setters, domain events, and proper encapsulation. Supports aggregate roots, child entities, and value objects.

dotnet-ef-core-configurationSkill

Generates Entity Framework Core configurations using Fluent API. Maps domain entities to database tables with proper relationships, constraints, and conventions.

dotnet-legacy-api-controllersSkill

Generates RESTful API Controllers with proper routing, versioning, authorization, and MediatR integration. Follows REST conventions and Clean Architecture patterns.

dotnet-minimal-api-endpointsSkill

Generates Minimal API endpoints following Microsoft's recommended approach. Creates fast, testable HTTP APIs with minimal code using MapGet/MapPost/MapPut/MapDelete. Preferred over controller-based APIs for new projects.

dotnet-result-patternSkill

Implements the Result pattern for explicit error handling without exceptions. Provides Result, Result<T>, and Error types for clean, predictable control flow in domain-driven applications.