EF Code First模式下如何单次生成符合规则的唯一QuotationNo字段值
更简便的QuotationNo生成方案
针对你目前两次调用SaveChanges生成QuotationNo的场景,有几种更简洁的实现方式:
1. 简化现有代码(无需显式Update)
你的现有代码里,第二次调用SaveChanges前不需要执行_db.Quotations.Update(quot)——因为实体添加并执行SaveChanges后,EF Core仍在跟踪该实体的状态,直接修改属性后调用SaveChanges,EF会自动生成更新语句。简化后的代码如下:
if (ModelState.IsValid) { _db.Quotations.Add(quot); _db.SaveChanges(); // 获取自增主键ID // 直接修改被跟踪的实体属性 quot.QuotationNo = $"QUOT/{DateTime.Today:MM-yy}/{quot.Id:D5}"; _db.SaveChanges(); // 自动触发更新,无需显式调用Update }
2. 数据库计算列(推荐,彻底避免两次SaveChanges)
如果你的数据库支持计算列(如SQL Server、PostgreSQL),可以将QuotationNo设为持久化计算列,由数据库自动生成格式值,业务代码只需一次SaveChanges即可完成操作。
操作步骤:
(1)修改实体类
给QuotationNo添加特性,告知EF该列由数据库维护:
public class Quotation { [Key] public int Id { get; set; } // PK [DatabaseGenerated(DatabaseGeneratedOption.Computed)] public string QuotationNo { get; set; } // 由数据库自动生成格式值 }
(2)配置计算列
- 若使用SQL Server,直接执行SQL语句修改表:
ALTER TABLE Quotations ADD QuotationNo AS 'QUOT/' + FORMAT(GETDATE(), 'MM-yy') + '/' + RIGHT('00000' + CAST(Id AS VARCHAR(5)), 5) PERSISTED;
- 若使用Code First,可在
DbContext的OnModelCreating中配置:
protected override void OnModelCreating(ModelBuilder modelBuilder) { modelBuilder.Entity<Quotation>() .Property(q => q.QuotationNo) .HasComputedColumnSql("'QUOT/' + FORMAT(GETDATE(), 'MM-yy') + '/' + RIGHT('00000' + CAST(Id AS VARCHAR(5)), 5)", stored: true); }
配置完成后,添加Quotation实体并调用一次SaveChanges,数据库会自动生成符合格式的QuotationNo,无需额外更新操作。
3. 封装逻辑到DbContext的SaveChanges方法
如果不想修改数据库结构,可以将生成QuotationNo的逻辑封装到DbContext的SaveChanges重写中,让业务代码更简洁:
public override int SaveChanges(bool acceptAllChangesOnSuccess) { // 筛选出所有新增状态的Quotation实体 var addedQuotations = ChangeTracker.Entries<Quotation>() .Where(e => e.State == EntityState.Added) .ToList(); // 先执行基础SaveChanges获取自增ID var result = base.SaveChanges(acceptAllChangesOnSuccess); // 为新增实体设置QuotationNo并标记为修改状态 foreach (var entry in addedQuotations) { var quot = entry.Entity; quot.QuotationNo = $"QUOT/{DateTime.Today:MM-yy}/{quot.Id:D5}"; entry.State = EntityState.Modified; } // 再次保存更新 if (addedQuotations.Any()) { result += base.SaveChanges(acceptAllChangesOnSuccess); } return result; }
业务代码只需调用一次SaveChanges即可:
if (ModelState.IsValid) { _db.Quotations.Add(quot); _db.SaveChanges(); // 内部自动完成两次保存逻辑 }
内容的提问来源于stack exchange,提问作者Lakshitha Kanchana
相关产品推荐
相关产品推荐

