DDD + CQRS + MediatR 專案架構

// ───────────────────────────────────────────── // Application/HumanResources/Queries/GetEmployeeList/ // ─────────────────────────────────────────────

public class EmployeeListQuery : IRequest<PagedResult> { public int Page { get; set; } = 1; public int PageSize { get; set; } = 10; public string? Keyword { get; set; } }

public class EmployeeListQueryHandler : IRequestHandler<EmployeeListQuery, PagedResult> { private readonly IEmployeeRepository _repository;

public EmployeeListQueryHandler(IEmployeeRepository repository)
{
    _repository = repository;
}

public async Task<PagedResult<EmployeeDto>> Handle(EmployeeListQuery request, CancellationToken cancellationToken)
{
    var (items, total) = await _repository.SearchAsync(request.Keyword, request.Page, request.PageSize);

    var result = new PagedResult<EmployeeDto>
    {
        TotalCount = total,
        Items = items.Select(e => new EmployeeDto
        {
            Id = e.Id,
            Name = e.Name,
            Department = e.Department,
            HireDate = e.HireDate
        }).ToList()
    };

    return result;
}

}

// ───────────────────────────────────────────── // Application/Common/Models/PagedResult.cs // ─────────────────────────────────────────────

public class PagedResult { public int TotalCount { get; set; } public List Items { get; set; } = new(); }

// ───────────────────────────────────────────── // Application/Common/Interfaces/IEmployeeRepository.cs // ─────────────────────────────────────────────

public interface IEmployeeRepository { Task<(List, int)> SearchAsync(string? keyword, int page, int pageSize); Task AddAsync(Employee employee); Task<Employee?> GetByIdAsync(Guid id); }

// ───────────────────────────────────────────── // Domain/Entities/Employee.cs // ─────────────────────────────────────────────

public class Employee { public Guid Id { get; private set; } public string Name { get; private set; } public string Department { get; private set; } public DateTime HireDate { get; private set; }

}

// ───────────────────────────────────────────── // Application/HumanResources/Queries/GetEmployeeById/ // ─────────────────────────────────────────────

public record GetEmployeeByIdQuery(Guid Id) : IRequest;

public class GetEmployeeByIdHandler : IRequestHandler<GetEmployeeByIdQuery, EmployeeDto> { private readonly IEmployeeRepository _repository;

}

// ───────────────────────────────────────────── // Application/HumanResources/Commands/CreateEmployee/ // ─────────────────────────────────────────────

public class CreateEmployeeDto { public string Name { get; set; } = string.Empty; public string Department { get; set; } = string.Empty; public DateTime HireDate { get; set; } }

public class CreateEmployeeValidator : AbstractValidator { public CreateEmployeeValidator() { RuleFor(x => x.Name).NotEmpty(); RuleFor(x => x.Department).NotEmpty(); RuleFor(x => x.HireDate).LessThanOrEqualTo(DateTime.Today); } }

public record CreateEmployeeCommand(CreateEmployeeDto Dto) : IRequest;

public class CreateEmployeeHandler : IRequestHandler<CreateEmployeeCommand, Guid> { private readonly IEmployeeRepository _repository;

}

// ───────────────────────────────────────────── // Application/HumanResources/EmployeeDto.cs // ─────────────────────────────────────────────

public class EmployeeDto { public Guid Id { get; set; } public string Name { get; set; } = string.Empty; public string Department { get; set; } = string.Empty; public DateTime HireDate { get; set; } }

// ───────────────────────────────────────────── // Infrastructure/Persistence/Repositories/EmployeeRepository.cs // ─────────────────────────────────────────────

public class EmployeeRepository : IEmployeeRepository { private readonly ApplicationDbContext _context;

}

// ───────────────────────────────────────────── // API/Controllers/HumanResourcesController.cs // ─────────────────────────────────────────────

[ApiController] [Route("api/[controller]")] [Produces("application/json")] [ApiExplorerSettings(GroupName = "Human Resources")] public class HumanResourcesController : ControllerBase { private readonly ISender _sender;

}

Last updated