C#模型构造函数初始化CreatedAt与Guid,MVC更新不覆盖的实现是否有效
这种实现方式不可行,存在不少问题
先直接给结论:你当前的构造函数实现没法满足「创建时初始化CreatedAt和UUId,更新时不覆盖」的需求,具体问题出在这几点:
UUId会被反复覆盖
每次实例化实体(包括EF从数据库加载实体的时候),构造函数都会执行this.UUId = new Guid();,这意味着你从数据库取出的实体,UUId会被替换成新值,一旦保存就会把数据库里的原始UUId覆盖掉,完全不符合预期。UpdatedAt时机不对
只要实例化实体,UpdatedAt就会被设为当前时间——哪怕你只是加载了实体看一眼,根本没做任何修改,保存的时候这个值也会被更新,这显然不是你想要的「只有更新操作时才更新UpdatedAt」的逻辑。CreatedAt的判断逻辑场景不匹配
虽然你加了if(this.CreatedAt == null)的判断,但构造函数是在实例化时执行,而非保存到数据库时执行。比如你先实例化一个实体,过了几分钟才保存,这时候CreatedAt会是实例化的时间,而不是真正入库的时间,可能和你的需求有偏差。
正确的实现方式:利用EF的生命周期钩子
更好的做法是在DbContext的SaveChanges(或异步版本SaveChangesAsync)方法里处理,根据实体的状态区分新增和修改操作:
public override int SaveChanges() { var currentTime = DateTimeOffset.Now; // 遍历所有继承自EntityBase的实体变更记录 foreach (var entityEntry in ChangeTracker.Entries<EntityBase>()) { switch (entityEntry.State) { // 新增实体时:初始化CreatedAt、UUId、UpdatedAt case EntityState.Added: entityEntry.Entity.CreatedAt = currentTime; entityEntry.Entity.UUId = Guid.NewGuid(); entityEntry.Entity.UpdatedAt = currentTime; break; // 修改实体时:只更新UpdatedAt,同时锁定CreatedAt和UUId不被修改 case EntityState.Modified: entityEntry.Entity.UpdatedAt = currentTime; // 标记这两个属性为未修改,避免被覆盖 entityEntry.Property(e => e.CreatedAt).IsModified = false; entityEntry.Property(e => e.UUId).IsModified = false; break; } } return base.SaveChanges(); }
这种方式的优势在于:
- 只有在真正保存数据的时候才会处理时间戳和UUId,完全贴合业务逻辑的时机
- 新增和修改操作的逻辑完全隔离,不会互相干扰
- 从根本上避免了实例化实体时误修改已有属性的问题
内容的提问来源于stack exchange,提问作者Dninja
相关产品推荐
相关产品推荐

