EF Core保存含重复关联实体的Schedule时的跟踪错误优化方案
更优解决方案
1. 仅传递FilmId(推荐)
既然Film已存在于数据库,无需传递完整实体,只保留FilmId即可。EF Core会通过外键自动关联现有Film,不会创建重复跟踪实例。
修改后的输入JSON:
{ "Id": 0, "Date": "10.06.2023", "Sessions": [ { "Id": 0, "Time": "10:00", "ScheduleId": 0, "FilmId": 11 }, { "Id": 0, "Time": "12:00", "ScheduleId": 0, "FilmId": 11 } ] }
接口代码无需修改,直接调用_context.Add(schedule)即可完成关联。
2. 合并重复的Film实例(适配前端必须传完整实体的场景)
如果前端必须传递完整Film对象,可在添加到上下文前,将所有Session的Film引用指向同一个实例,确保EF仅跟踪一个对象。
修改接口代码:
[HttpPost] [Consumes("application/json")] public async Task<IActionResult> Add([FromBody] Schedule schedule) { if (!ModelState.IsValid) { return Json(new { success = false }); } // 按Film Id分组,合并相同Id的Film引用 var filmGroups = schedule.Sessions .Where(s => s.Film != null && s.Film.Id > 0) .GroupBy(s => s.Film.Id); foreach (var group in filmGroups) { var sharedFilm = group.First().Film; foreach (var session in group.Skip(1)) { session.Film = sharedFilm; } } _context.Add(schedule); await _context.SaveChangesAsync(); return Json(new { success = true, model = schedule }); }
3. 手动附加现有Film实例(确保数据一致性)
如果需要确保使用数据库中最新的Film数据,可先从上下文获取或附加Film,再让Session引用该实例。
修改接口代码:
[HttpPost] [Consumes("application/json")] public async Task<IActionResult> Add([FromBody] Schedule schedule) { if (!ModelState.IsValid) { return Json(new { success = false }); } // 获取所有唯一的Film Id var uniqueFilmIds = schedule.Sessions.Select(s => s.FilmId).Distinct(); foreach (var filmId in uniqueFilmIds) { // 检查上下文是否已跟踪该Film,未跟踪则从数据库获取 var trackedFilm = _context.Films.Local.FirstOrDefault(f => f.Id == filmId); var targetFilm = trackedFilm ?? await _context.Films.FindAsync(filmId); if (targetFilm == null) { return Json(new { success = false, message = $"Film {filmId}不存在" }); } // 让所有对应Session引用这个已跟踪的实例 foreach (var session in schedule.Sessions.Where(s => s.FilmId == filmId)) { session.Film = targetFilm; } } _context.Add(schedule); await _context.SaveChangesAsync(); return Json(new { success = true, model = schedule }); }
临时方案的弊端
- Detach方案:可能破坏上下文对
Film的跟踪状态,导致后续操作出现数据不一致问题。 - 置空Film方案:后续访问
Session.Film时会触发NullReferenceException,影响代码健壮性。
内容的提问来源于stack exchange,提问作者Alfredo
相关产品推荐
相关产品推荐

