Blazor搭配EF为导航属性赋值时出现Ships表IDENTITY_INSERT报错如何解决
问题根源
EF Core将你传入的Ship导航属性实例识别为需要新增的实体,尝试向Ships表插入带指定Id的Ship记录,而Ships表的Id是自增标识列,默认不允许手动插入Id值,所以抛出该错误。你之前的解决方案无效的原因也很明确:
- 开启
IDENTITY_INSERT时选错了表,报错指向的是Ships表,你操作的是Reservations表 [DatabaseGenerated]和ValueGeneratedNever()都是给字段属性用的,无法作用于导航属性
最优解决方案(推荐)
步骤1:修改Reservation实体,删除不必要的初始化并增加显式外键
Reservation构造函数里默认初始化new Ship()会导致即使你没赋值Ship,EF也会跟踪到一个空的Ship实例识别为新增,先删除这段逻辑,同时增加显式的ShipId外键字段,避免依赖导航属性做关联更可靠:
public class Reservation { // 删除默认初始化Ship的代码 public int Id { get; set; } public DateTime FromDate { get; set; } public DateTime ToDate { get; set; } // 新增显式外键字段 public int ShipId { get; set; } public Ship Ship { get; set; } }
步骤2:调整DTO结构,只传关联外键不要传整个导航对象
修改ReservationPostDTO,把Ship属性替换为ShipId,不需要传递完整的Ship对象:
public class ReservationPostDTO { public DateTime FromDate { get; set; } public DateTime ToDate { get; set; } public int ShipId { get; set; } // 保留其他需要的字段即可 }
步骤3:修改Razor页面提交逻辑,只赋值外键
async void HandleSubmit() { reservation.ShipId = SelectedShip.Id; await ReservationService.CreateReservation(reservation); }
兼容解决方案(不想改现有DTO结构可采用)
如果你暂时不想调整DTO和实体结构,也可以在保存前手动告诉EF,这个Ship实例是已存在的,不需要新增:
[HttpPost] public async Task<IActionResult> CreateReservation(ReservationGetDTO reservationDTO) { var reservation = Mapper.Map(reservationDTO, new Reservation()); // 手动设置Ship实例的跟踪状态为未修改,EF就不会尝试插入新的Ship记录 _context.Attach(reservation.Ship).State = EntityState.Unchanged; _context.Reservations.Add(reservation); await _context.SaveChangesAsync(); return await GetReservations(); }
额外优化点:你OnModelCreating里的关联配置重复了,Reservation和Ship的一对多关系配置一遍即可,重复配置不影响运行但属于冗余代码可以删除。
内容的提问来源于stack exchange,提问作者Rena821
相关产品推荐
相关产品推荐

