使用EF Core 7删除数据库子表记录问题求助
问题:EF Core 7中通过导航集合删除子实体不生效
我采用仓储模式结合UnitOfWork,聚合根ParentTable与ChildOne、ChildTwo表关联。执行以下代码后,ParentTable的行能成功更新,但指定的ChildTwo子实体并未被删除。尝试过多种在线方案都没用,且EF Core 7里找不到用于标记删除的Attach方法。
ParentTable? parentTable = await _unitOfWork.ParentRepository.GetSingleAsync(ParentId); if (parentTable == null) return false; List<ChildTwo> childrenToDelete = new() { new ChildTwo { ChildTwoId = 3, ParentId = parentTable.ParentId }, new ChildTwo { ChildTwoId = 4, ParentId = parentTable.ParentId } }; parentTable.Name = "Parent Name Updated"; foreach (var T in childrenToDelete) parentTable.ChildTwo.Remove(T); await _unitOfWork.SaveChangesAsync();
问题原因
你手动创建的ChildTwo实例不在EF Core的跟踪上下文中,调用Remove方法时,EF无法识别这些是需要删除的数据库实体,只会移除内存中的集合项,不会同步到数据库。
解决方案
方案1:加载已跟踪的子实体后删除
查询父实体时,通过Include加载关联的ChildTwo集合,确保子实体被EF跟踪,再从已跟踪集合中筛选移除:
// 查询时Include加载ChildTwo集合,确保子实体被跟踪 ParentTable? parentTable = await _unitOfWork.ParentRepository.GetSingleAsync( ParentId, include => include.Include(p => p.ChildTwo) ); if (parentTable == null) return false; parentTable.Name = "Parent Name Updated"; // 从已跟踪的集合中筛选要删除的子实体 var targetChildIds = new[] { 3, 4 }; var childrenToDelete = parentTable.ChildTwo .Where(c => targetChildIds.Contains(c.ChildTwoId)) .ToList(); foreach (var child in childrenToDelete) parentTable.ChildTwo.Remove(child); await _unitOfWork.SaveChangesAsync();
方案2:直接标记实体为删除状态
EF Core 7支持直接将未跟踪实体标记为Deleted状态,无需使用Attach:
ParentTable? parentTable = await _unitOfWork.ParentRepository.GetSingleAsync(ParentId); if (parentTable == null) return false; parentTable.Name = "Parent Name Updated"; var targetChildIds = new[] { 3, 4 }; foreach (var id in targetChildIds) { // 创建仅包含主键和外键的实体 var child = new ChildTwo { ChildTwoId = id, ParentId = parentTable.ParentId }; // 直接标记为删除状态 _unitOfWork.DbContext.Entry(child).State = EntityState.Deleted; } await _unitOfWork.SaveChangesAsync();
注:需要确保你的UnitOfWork暴露了DbContext实例,或者在仓储中封装该逻辑。
方案3:封装批量删除的仓储方法
如果频繁需要批量删除子实体,可以在ChildTwo仓储中添加专门的删除方法:
仓储接口与实现
// 仓储接口 public interface IChildTwoRepository { Task DeleteRangeByParentAndIdsAsync(IEnumerable<int> childIds, int parentId); } // 仓储实现 public class ChildTwoRepository : IChildTwoRepository { private readonly AppDbContext _dbContext; public ChildTwoRepository(AppDbContext dbContext) { _dbContext = dbContext; } public async Task DeleteRangeByParentAndIdsAsync(IEnumerable<int> childIds, int parentId) { var childrenToDelete = await _dbContext.ChildTwo .Where(c => childIds.Contains(c.ChildTwoId) && c.ParentId == parentId) .ToListAsync(); _dbContext.ChildTwo.RemoveRange(childrenToDelete); } }
业务代码中调用
ParentTable? parentTable = await _unitOfWork.ParentRepository.GetSingleAsync(ParentId); if (parentTable == null) return false; parentTable.Name = "Parent Name Updated"; await _unitOfWork.ChildTwoRepository.DeleteRangeByParentAndIdsAsync(new[] {3,4}, parentTable.ParentId); await _unitOfWork.SaveChangesAsync();
内容的提问来源于stack exchange,提问作者Alisbha Khan
相关产品推荐
相关产品推荐

