Receber por email
← Voltar para o catálogo

dotnet-domain-entity-generator

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

66estrelas
Atualizado há 5 meses

Ver no GitHub ↗

Como adicionar

/plugin marketplace add ronnythedev/dotnet-clean-architecture-skills

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/dotnet-domain-entity-generator/svg)](https://www.skillteca.com.br/skills/dotnet-domain-entity-generator)

Skills relacionadas

Ver todas de Desenvolvimento →

Alerta por categoria

Receba novas skills de Desenvolvimento toda segunda

1 email curto, só com as skills novas de Desenvolvimento. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Domain Entity Generator

Overview

This skill generates Domain Entities following Domain-Driven Design (DDD) principles:

  • Encapsulation - Private setters, controlled modification
  • Factory Methods - Static Create() methods with validation
  • Domain Events - State changes raise events
  • Rich Domain Model - Behavior lives in the entity, not services
  • Invariant Protection - Entity always in valid state

Quick Reference

| Concept | Purpose | Example | |---------|---------|---------| | Aggregate Root | Entry point for aggregate | Organization, User | | Child Entity | Part of aggregate, no own identity outside | OrderItem, AssessmentDetail | | Value Object | Immutable, no identity | Email, Money, Address | | Domain Event | Signal state change | UserCreatedDomainEvent |

Entity Structure

/Domain/{Aggregate}/
├── {Entity}.cs                    # Main entity
├── {Entity}Errors.cs              # Typed errors
├── I{Entity}Repository.cs         # Repository interface
├── ValueObjects/
│   ├── {ValueObject}.cs
│   └── ...
└── Events/
    ├── {Entity}CreatedDomainEvent.cs
    ├── {Entity}UpdatedDomainEvent.cs
    └── ...

Template: Aggregate Root Entity

// src/{name}.domain/{Aggregate}/{Entity}.cs
using {name}.domain.abstractions;
using {name}.domain.{aggregate}.events;

namespace {name}.domain.{aggregate};

public sealed class {Entity} : Entity
{
    // ═══════════════════════════════════════════════════════════════
    // PRIVATE COLLECTIONS (encapsulated)
    // ═══════════════════════════════════════════════════════════════
    private readonly List<{ChildEntity}> _{childEntities} = new();

    // ═══════════════════════════════════════════════════════════════
    // PROPERTIES (private setters)
    // ═══════════════════════════════════════════════════════════════
    public string Name { get; private set; }
    public string? Description { get; private set; }
    public bool IsActive { get; private set; }
    public DateTime CreatedAt { get; private set; }
    public DateTime UpdatedAt { get; private set; }
    
    // Navigation property (read-only collection)
    public IReadOnlyCollection<{ChildEntity}> {ChildEntities} => _{childEntities}.AsReadOnly();

    // ═══════════════════════════════════════════════════════════════
    // CONSTRUCTORS
    // ═══════════════════════════════════════════════════════════════
    
    // Private constructor for EF Core
    private {Entity}() { }

    // Private constructor for factory method
    private {Entity}(
        Guid id,
        string name,
        string? description,
        DateTime createdAt)
        : base(id)
    {
        Name = name;
        Description = description;
        IsActive = true;
        CreatedAt = createdAt;
        UpdatedAt = createdAt;
    }

    // ═══════════════════════════════════════════════════════════════
    // FACTORY METHODS
    // ═══════════════════════════════════════════════════════════════
    
    /// <summary>
    /// Creates a new {Entity} with validation
    /// </summary>
    public static Result<{Entity}> Create(
        string name,
        string? description,
        DateTime createdAt)
    {
        // Validate invariants
        if (string.IsNullOrWhiteSpace(name))
        {
            return Result.Failure<{Entity}>({Entity}Errors.NameIsRequired);
        }

        if (name.Length > 100)
        {
            return Result.Failure<{Entity}>({Entity}Errors.NameTooLong);
        }

        var {entity} = new {Entity}(
            Guid.NewGuid(),
            name,
            description,
            createdAt);

        // Raise domain event
        {entity}.RaiseDomainEvent(new {Entity}CreatedDomainEvent({entity}.Id));

        return {entity};
    }

    // ═══════════════════════════════════════════════════════════════
    // DOMAIN METHODS
    // ═══════════════════════════════════════════════════════════════
    
    /// <summary>
    /// Updates the {Entity} properties
    /// </summary>
    public Result Update(
        string name,
        string? description,
        DateTime updatedAt)
    {
        if (string.IsNullOrWhiteSpace(name))
        {
            return Result.Failure({Entity}Errors.NameIsRequired);
        }

        if (name.Length > 100)
        {
            return Result.Failure({Entity}Errors.NameTooLong);
        }

        Name = name;
        Description = description;
        UpdatedAt = updatedAt;

        RaiseDomainEvent(new {Entity}UpdatedDomainEvent(Id));

        return Result.Success();
    }

    /// <summary>
    /// Deactivates the {Entity}
    /// </summary>
    public Result Deactivate(DateTime updatedAt)
    {
        if (!IsActive)
        {
            return Result.Failure({Entity}Errors.AlreadyDeactivated);
        }

        IsActive = false;
        UpdatedAt = updatedAt;

        RaiseDomainEvent(new {Entity}DeactivatedDomainEvent(Id));

        return Result.Success();
    }

    /// <summary>
    /// Reactivates the {Entity}
    /// </summary>
    public Result Activate(DateTime updatedAt)
    {
        if (IsActive)
        {
            return Result.Failure({Entity}Errors.AlreadyActive);
        }

        IsActive = true;
        UpdatedAt = updatedAt;

        return Result.Success();
    }

    // ═══════════════════════════════════════════════════════════════
    // CHILD ENTITY MANAGEMENT
    // ═══════════════════════════════════════════════════════════════
    
    /// <summary>
    /// Adds a child entity to this aggregate
    /// </summary>
    public Result Add{ChildEntity}({ChildEntity} {childEntity})
    {
        if ({childEntity} is null)
        {
            return Result.Failure({Entity}Errors.Child{ChildEntity}Required);
        }

        if (_{childEntities}.Any(c => c.Name == {childEntity}.Name))
        {
            return Result.Failure({Entity}Errors.Duplicate{ChildEntity}Name);
        }

        _{childEntities}.Add({childEntity});

        RaiseDomainEvent(new {ChildEntity}AddedDomainEvent(Id, {childEntity}.Id));

        return Result.Success();
    }

    /// <summary>
    /// Removes a child entity from this aggregate
    /// </summary>
    public Result Remove{ChildEntity}(Guid {childEntity}Id)
    {
        var {childEntity} = _{childEntities}.FirstOrDefault(c => c.Id == {childEntity}Id);

        if ({childEntity} is null)
        {
            return Result.Failure({Entity}Errors.{ChildEntity}NotFound);
        }

        _{childEntities}.Remove({childEntity});

        return Result.Success();
    }

    // ═══════════════════════════════════════════════════════════════
    // QUERY METHODS
    // ═══════════════════════════════════════════════════════════════
    
    public bool HasActiveChildren() => _{childEntities}.Any(c => c.IsActive);

    public {ChildEntity}? GetChildById(Guid childId) => 
        _{childEntities}.FirstOrDefault(c => c.Id == childId);
}

Template: Child Entity (Part of Aggregate)

// src/{name}.domain/{Aggregate}/{ChildEntity}.cs
using {name}.domain.abstractions;

namespace {name}.domain.{aggregate};

public sealed class {ChildEntity} : Entity
{
    // ═══════════════════════════════════════════════════════════════
    // PROPERTIES
    // ═══════════════════════════════════════════════════════════════
    public Guid {Parent}Id { get; private set; }
    public string Name { get; private set; }
    public string? Description { get; private set; }
    public int SortOrder { get; private set; }
    public bool IsActive { get; private set; }
    public DateTime CreatedAt { get; private set; }
    public DateTime UpdatedAt { get; private set; }

    // Navigation property
    public {Parent} {Parent} { get; private set; } = null!;

    // ═══════════════════════════════════════════════════════════════
    // CONSTRUCTORS
    // ═══════════════════════════════════════════════════════════════
    
    private {ChildEntity}() { } // EF Core
Compartilhar X LinkedIn