EF Core中数据库插入完成后为属性分配标识ID的实现方案及ref关键字可行性咨询
如何在EF Core保存实体后获取自动生成ID并同步到DTO?
这是个很常见的EF Core使用误区,我来帮你理清楚问题所在和解决方案:
为什么当前代码里trainingPlan.ResourceId始终是0?
因为你在调用SaveChangesAsync()之前就给trainingPlan.ResourceId赋值了——此时tp.Id还是EF Core给值类型主键的默认初始值(int类型就是0)。只有当SaveChangesAsync()执行完成后,EF Core才会把数据库自动生成的主键ID回填到tp对象的Id属性里,你提前赋值自然拿不到真实的ID。
能不能用ref关键字解决这个问题?
其实完全没必要,而且这也不是ref关键字的适用场景。ref主要用于在方法间传递值类型的引用,但你的tp是引用类型,SaveChanges后EF会自动更新tp.Id的值,你只需要调整赋值的时机就能解决问题,根本不需要用ref来复杂化方法设计。
正确的解决方案
只需要把trainingPlan.ResourceId = tp.Id;这行代码移到SaveChangesAsync()执行之后就可以了:
public async Task<TrainingPlan> CreateTrainingPlan(TrainingPlanDTO trainingPlan) { TrainingPlan tp = new TrainingPlan { Name = trainingPlan.Name }; // 添加到上下文 _context.TrainingPlan.Add(tp); // 先执行保存,EF会自动把数据库生成的ID回填到tp.Id await _context.SaveChangesAsync(); // 现在tp.Id已经是数据库生成的真实ID了 trainingPlan.ResourceId = tp.Id; // 上下文如果还有其他实体要保存,这里可以继续处理(不过建议尽量批量保存) return tp; }
额外注意事项
要确保你的TrainingPlan实体的Id属性是配置为数据库自动生成的:
- 用DataAnnotations的方式:
public class TrainingPlan { [DatabaseGenerated(DatabaseGeneratedOption.Identity)] public int Id { get; set; } public string Name { get; set; } } - 或者用Fluent API的方式(在DbContext的
OnModelCreating方法里):protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<TrainingPlan>() .Property(t => t.Id) .ValueGeneratedOnAdd(); }
如果没有这个配置,EF Core不会自动回填数据库生成的ID,那你还是拿不到正确的值。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

