如何在.NET Core泛型仓储中基于表达式实现Lookup表的FindByID功能
现有代码存在的问题
- 仓储层
GetById方法调用Where返回的是IQueryable<T>集合,直接映射会得到错误结果,且未实现异步逻辑 - 服务层方法未声明
predicate参数、未加async标记,且查询操作不需要调用_unitOfWork.CompleteAsync()(仅增删改需要提交事务) - 控制器的接口未接收前端传入的Id参数,路由配置不符合Restful规范
修正后的实现方案
1. 增加Lookup实体统一约束
先定义公共接口,保证所有Lookup表都有Id和Value字段,方便泛型约束:
public interface ILookupEntity { int Id { get; set; } string Value { get; set; } }
给所有Lookup实体实现该接口:
public partial class LutGender : ILookupEntity { public int Id { get; set; } public string Value { get; set; } } public partial class LutNationality : ILookupEntity { public int Id { get; set; } public string Value { get; set; } }
2. 修正泛型仓储实现
建议直接封装Id查询逻辑,避免外部传入不合理的表达式影响性能:
// 泛型仓储接口增加约束 public interface IGenericRepository<T> where T : class, ILookupEntity { Task<GenericLookupDTO> GetByIdAsync(int id); } // 仓储实现 public class GenericRepository<T> : IGenericRepository<T> where T : class, ILookupEntity { private readonly NexusContext _context; public GenericRepository(NexusContext context) { _context = context; } public async Task<GenericLookupDTO> GetByIdAsync(int id) { var obj = await _context.Set<T>().FirstOrDefaultAsync(x => x.Id == id); return AutoMapping.mapper.Map<GenericLookupDTO>(obj); } }
3. 修正服务层实现
补全方法签名和异步标记:
// 服务接口定义 public interface IConfigurationService<T> where T : class, ILookupEntity { Task<GenericResponse<GenericLookupDTO>> GetByIdAsync(int id); } // 服务实现 public class ConfigurationService<T> : IConfigurationService<T> where T : class, ILookupEntity { private readonly IGenericRepository<T> _genericRepository; private readonly IUnitOfWork _unitOfWork; public ConfigurationService(IGenericRepository<T> genericRepository, IUnitOfWork unitOfWork) { _genericRepository = genericRepository; _unitOfWork = unitOfWork; } public async Task<GenericResponse<GenericLookupDTO>> GetByIdAsync(int id) { List<Errors> errors = new List<Errors>(); try { var obj = await _genericRepository.GetByIdAsync(id); if (obj == null) { errors.Add(new Errors("404", "Couldn't find configuration")); return new GenericResponse<GenericLookupDTO>(errors, new GenericLookupDTO()); } return new GenericResponse<GenericLookupDTO>("1", "Success", obj); } catch (Exception ex) { var errorMsg = ex.InnerException?.Message ?? ex.Message; errors.Add(new Errors(ex.HResult.ToString(), errorMsg)); return new GenericResponse<GenericLookupDTO>(errors, new GenericLookupDTO()); } } }
4. 修正控制器调用逻辑
private readonly IConfigurationService<LutNationality> _configurationService; public NationalityController(IConfigurationService<LutNationality> configurationService) { _configurationService = configurationService; } // 路由配置接收id参数,比如请求地址为 GET /Nationality/1 [HttpGet("{id:int}")] [ProducesResponseType(typeof(GenericLookupDTO), (int)HttpStatusCode.OK)] public async Task<IActionResult> GetByIdAsync([FromRoute] int id) { var result = await _configurationService.GetByIdAsync(id); if (result.operationSuccess) return Ok(result); return BadRequest(result); }
若坚持使用表达式传参的方案
如果要保留原有的表达式参数设计,控制器调用时直接传入匹配条件即可:
var result = await _configurationService.GetByIdAsync(x => x.Id == id);
内容的提问来源于stack exchange,提问作者Jed
相关产品推荐
相关产品推荐

