ASP.NET Core Web API清洁架构下如何获取含部门名的员工数据?
清洁架构下获取关联实体数据的解决方案
核心思路
清洁架构的核心是依赖倒置原则:Core层定义抽象契约,外层(Infrastructure、Application)依赖Core层实现具体逻辑。针对你的需求,我们可以通过「Core层定义抽象查询模型,Infrastructure层实现数据查询映射,Application层处理业务DTO转换」的方式,既遵守架构边界,又满足获取带DepartmentName的Employee数据的需求。
分步实现
1. Core层:定义抽象查询模型与仓储接口
Core层仅存放领域实体和抽象契约,不依赖任何外层。我们定义一个只读的查询模型接口,描述需要的关联数据结构,同时扩展仓储接口添加对应的抽象方法:
// Core/Models/IEmployeeWithDepartment.cs namespace YourProject.Core.Models; public interface IEmployeeWithDepartment { int Id { get; } string Name { get; } // 其他Employee核心字段 string DepartmentName { get; } } // Core/Repositories/IEmployeeRepository.cs namespace YourProject.Core.Repositories; public interface IEmployeeRepository { Task<IEnumerable<IEmployeeWithDepartment>> GetAllWithDepartmentAsync(); // 基础CRUD方法保持不变 }
2. Infrastructure层:实现查询逻辑与实体映射
Infrastructure层依赖Core层,负责具体的数据查询和映射。这里可以用EF Core的投影查询,将实体数据映射到Core层定义的查询模型(内部实现类仅在Infrastructure层可见):
// Infrastructure/Repositories/EmployeeRepository.cs namespace YourProject.Infrastructure.Repositories; public class EmployeeRepository : IEmployeeRepository { private readonly AppDbContext _dbContext; public EmployeeRepository(AppDbContext dbContext) { _dbContext = dbContext; } public async Task<IEnumerable<IEmployeeWithDepartment>> GetAllWithDepartmentAsync() { return await _dbContext.Employees .Join(_dbContext.Departments, emp => emp.DepartmentId, dept => dept.Id, (emp, dept) => new EmployeeWithDepartmentInternal { Id = emp.Id, Name = emp.Name, DepartmentName = dept.Name // 映射其他需要的字段 }) .ToListAsync(); } } // Infrastructure/Models/EmployeeWithDepartmentInternal.cs namespace YourProject.Infrastructure.Models; internal class EmployeeWithDepartmentInternal : IEmployeeWithDepartment { public int Id { get; set; } public string Name { get; set; } public string DepartmentName { get; set; } // 实现IEmployeeWithDepartment的所有属性 }
3. Application层:定义业务DTO与查询服务
Application层依赖Core层,负责定义对外暴露的业务DTO,并实现查询服务,将Core层的抽象查询模型转换为业务DTO:
// Application/Dtos/EmployeeWithDepartmentResponse.cs namespace YourProject.Application.Dtos; public class EmployeeWithDepartmentResponse { public int Id { get; set; } public string EmployeeName { get; set; } public string DepartmentName { get; set; } // 可根据业务需求调整字段名称或添加额外处理 } // Application/Services/EmployeeQueryService.cs namespace YourProject.Application.Services; public class EmployeeQueryService { private readonly IEmployeeRepository _employeeRepository; public EmployeeQueryService(IEmployeeRepository employeeRepository) { _employeeRepository = employeeRepository; } public async Task<IEnumerable<EmployeeWithDepartmentResponse>> GetAllEmployeesWithDepartmentAsync() { var employeeModels = await _employeeRepository.GetAllWithDepartmentAsync(); return employeeModels.Select(model => new EmployeeWithDepartmentResponse { Id = model.Id, EmployeeName = model.Name, DepartmentName = model.DepartmentName }); } }
4. Presentation层:API控制器调用服务
Presentation层依赖Application层,直接调用查询服务获取DTO并返回给前端:
// Presentation/Controllers/EmployeesController.cs namespace YourProject.Presentation.Controllers; [ApiController] [Route("api/employees")] public class EmployeesController : ControllerBase { private readonly EmployeeQueryService _employeeQueryService; public EmployeesController(EmployeeQueryService employeeQueryService) { _employeeQueryService = employeeQueryService; } [HttpGet("with-department")] public async Task<IActionResult> GetAllWithDepartment() { var response = await _employeeQueryService.GetAllEmployeesWithDepartmentAsync(); return Ok(response); } }
架构优势
- 严格遵守依赖规则:Core层无外部依赖,外层均依赖Core层,符合清洁架构的依赖倒置要求。
- 关注点分离:仓储仅负责数据查询与抽象模型映射,Application层处理业务DTO转换,Presentation层只负责API暴露,各层职责清晰。
- 可扩展性:如需新增其他关联数据,只需在Core层新增查询模型接口,Infrastructure层实现查询逻辑,Application层调整DTO转换即可,不影响现有代码结构。
内容的提问来源于stack exchange,提问作者Baubau Tran
相关产品推荐
相关产品推荐

