Entity Framework Core:如何返回已加载导航属性的新增对象
解决方案
你完全不需要额外执行一次查询,因为你已经在创建实体的过程中,把从数据库加载的OrderHeader实例添加到了Track的关联集合里,这些实例本身就被EF Core上下文追踪,SaveChanges之后,当前的entity对象已经包含完整的关联数据,直接用来转换响应即可。
优化后的代码(直接复用现有实体)
public async Task<TrackResponse> Handle(CreateTrackCommand request, CancellationToken cancellationToken) { Track entity = request.ToEntity(); foreach(string id in request.OrderHeaders) { OrderHeader dbEntity = await _db.OrderHeaders.FirstOrDefaultAsync(m => m.Id == id, cancellationToken) ?? throw new ResourceNotFoundException(nameof(OrderHeader), id); entity.OrderHeaders.Add(dbEntity); } _db.Tracks.Add(entity); await _db.SaveChangesAsync(cancellationToken); // 直接用已填充关联的实体转响应,省去二次查询 TrackResponse response = entity.ToResponse(); return response; }
额外优化:减少数据库查询次数
如果request.OrderHeaders的数量较多,循环查询会产生多次数据库请求,你可以一次性批量获取所有需要的OrderHeader,再添加到关联集合里,效率更高:
public async Task<TrackResponse> Handle(CreateTrackCommand request, CancellationToken cancellationToken) { Track entity = request.ToEntity(); // 一次性查询所有需要的OrderHeader var orderHeaders = await _db.OrderHeaders .Where(m => request.OrderHeaders.Contains(m.Id)) .ToListAsync(cancellationToken); // 检查是否有不存在的ID var missingIds = request.OrderHeaders.Except(orderHeaders.Select(m => m.Id)).ToList(); if(missingIds.Any()) { throw new ResourceNotFoundException(nameof(OrderHeader), string.Join(", ", missingIds)); } entity.OrderHeaders.AddRange(orderHeaders); _db.Tracks.Add(entity); await _db.SaveChangesAsync(cancellationToken); TrackResponse response = entity.ToResponse(); return response; }
原理说明
EF Core上下文会追踪所有通过它查询出来的实体,当你把这些追踪的OrderHeader添加到新创建的Track的关联集合时,EF Core会自动维护两者的关联关系。执行SaveChanges后,当前的entity对象的OrderHeaders集合已经包含完整的关联数据,完全不需要再去数据库重新查询一次。
内容的提问来源于stack exchange,提问作者Ariteku
相关产品推荐
相关产品推荐

