在.NET Core中创建含外键的实体时,能否仅设置外键字段无需查询关联实体?
完全可以跳过这步冗余的数据库查询。你当前仅设置StatusCode标量外键值的写法完全符合EF Core的运行机制,不会影响关联关系的正常写入。
你在实体上已经通过[ForeignKey("StatusCode")]明确声明:DeliveryStatus实体的StatusCode标量属性,是与DeliveryStatusText导航属性配对的外键字段。这种显式定义的独立外键属性,是EF Core识别实体关联的最高优先级依据:
- 执行实体新增、调用
SaveChanges时,EF Core会直接读取实体上已赋值的StatusCode值,生成对应INSERT语句,把外键值直接写入数据库表 - 整个写入过程不需要EF在变更追踪器中定位对应的
DeliveryStatusText主体实体,也不会为了关联关系额外发起任何数据库查询 - 你之前写的
await _db.DeliveryStatusText.FindAsync(0)代码,反而会带来两层额外开销:一是额外发起一次主键查询,二是会把查询到的DeliveryStatusText实体纳入DbContext的变更追踪,占用不必要的内存与追踪计算资源
常见认知误区:很多开发者误以为EF Core保存关联实体时,必须把对应的主体实体纳入上下文追踪才能正常保存。这个结论仅适用于没有显式声明独立外键标量属性的场景。只要你已经有独立的、可直接赋值的外键字段,EF Core根本不会在校验关联关系时去追踪主体实体的存在,只要标量值符合数据库外键约束要求,就能正常完成写入。
删掉冗余查询后,你的新增逻辑可以简化为:
DeliveryStatus status = new DeliveryStatus { DeliveryId = newDelivery.DeliveryId, StatusCode = 0, StatusTime = DateTime.Now }; _db.DeliveryStatus.Add(status); await _db.SaveChangesAsync();
只要数据库的DeliveryStatusText表中存在StatusCode = 0的记录,数据库层面的外键约束就会正常校验通过,关联关系完全有效。
只有当你后续在同一个DbContext实例中,需要不重新查库就直接读取status.DeliveryStatusText.StatusText的值时,才需要考虑给导航属性赋值。只要当前业务逻辑在创建DeliveryStatus时不需要立即访问导航属性的内容,就完全没有必要提前拉取关联实体。
如果确实需要在不查库的情况下让导航属性可访问,也不需要用FindAsync查询,直接new一个对应的DeliveryStatusText实例、把StatusCode赋值后附加到上下文即可,依然可以省去数据库查询开销。
内容的提问来源于stack exchange,提问作者Kristoffervt

