使用EFCore.BulkExtensions的BulkInsertOrUpdate正确维护时间字段
解决EFCore.BulkExtensions批量维护CreationTime和LatestUpdate字段的问题
问题分析
你当前的代码里,预先给LatestUpdate赋值为DateTime.Now,再用PropertiesToExcludeOnCompare排除它的比较逻辑,导致只要是更新操作,不管其他业务字段有没有变化,都会把预先设置的当前时间写入LatestUpdate,这不符合“仅其他字段变更时才更新”的需求。
正确实现方案
方案一:数据库层面维护(推荐,性能更优)
直接通过数据库默认值和触发器实现,不需要在代码里做额外配置:
- CreationTime配置:
- 数据库表中
CreationTime字段设置默认值为GETDATE() - 实体类中标记该字段为
[DatabaseGenerated(DatabaseGeneratedOption.Identity)],确保仅插入时生成值,更新时不修改
- 数据库表中
- LatestUpdate配置:
- 数据库表中
LatestUpdate字段设置默认值为GETDATE() - 创建UPDATE触发器,当记录的业务字段发生变更时,自动将
LatestUpdate更新为当前时间:CREATE TRIGGER TR_YourTable_UpdateLatestUpdate ON YourTable AFTER UPDATE AS BEGIN IF UPDATE(业务字段1) OR UPDATE(业务字段2) -- 替换为实际需要监控的业务字段 BEGIN UPDATE t SET t.LatestUpdate = GETDATE() FROM YourTable t INNER JOIN inserted i ON t.Id = i.Id END END
- 数据库表中
- 代码中只需保留
PropertiesToExcludeOnUpdate排除CreationTime即可:BulkInsertOrUpdate(Entities, new BulkConfig() { PropertiesToExcludeOnUpdate = new List<string>() { nameof(BaseEntity.CreationTime) } });
方案二:纯代码层面配置
如果不想依赖数据库触发器,可以通过EFCore.BulkExtensions的扩展配置实现:
- CreationTime配置:和方案一一致,确保仅插入时生成值
- LatestUpdate配置:
- 不要预先给
LatestUpdate赋值 - 通过
PropertiesToIncludeOnCompare指定用来判断是否需要更新的业务字段(排除CreationTime和LatestUpdate) - 通过
UpdateSqlExpression指定更新时动态设置LatestUpdate为当前时间
示例代码:
BulkInsertOrUpdate(Entities, new BulkConfig() { // 仅比较业务字段,判断是否需要更新 PropertiesToIncludeOnCompare = new List<string>() { nameof(BaseEntity.Name), // 替换为实际业务字段 nameof(BaseEntity.Age) // 其他业务字段... }, PropertiesToExcludeOnUpdate = new List<string>() { nameof(BaseEntity.CreationTime) }, // 更新时自动设置LatestUpdate为当前时间(SQL Server语法) UpdateSqlExpression = "LatestUpdate = GETDATE()" }); - 不要预先给
原理说明
PropertiesToIncludeOnCompare会指定哪些字段用来对比判断记录是否需要更新,只有这些字段发生变化时,才会触发更新操作UpdateSqlExpression会在更新操作执行时,动态执行指定的SQL语句设置LatestUpdate,避免预先赋值导致的无意义更新
内容的提问来源于stack exchange,提问作者GIovanni
相关产品推荐
相关产品推荐

