如何移除Switch中重复LINQ逻辑,优化动态数据库列更新代码?
可以优化,这里给你几种简洁高效的实现方式
首先提一下你现有代码的小问题:原来的Select里每次迭代都会调用DateTime.UtcNow,可能导致不同实体的更新时间有细微差异,不符合你“单次请求内所有Id用同一UTC时间”的要求,优化时会一并修正。
方法一:委托字典映射(性能最优)
提前把列名和对应的属性赋值逻辑存到字典里,后续直接调用即可,新增列只需要在字典里加一行:
// 提前定义(可放在类的静态字段里,只初始化一次) private static readonly Dictionary<string, Action<YourEntityType, DateTime>> _columnSetters = new() { { "DataA", (entity, time) => entity.DataA = time }, { "DataB", (entity, time) => entity.DataB = time }, { "DataC", (entity, time) => entity.DataC = time } // 新增列直接在这里加对应项 }; // 处理请求时的代码 var utcNow = DateTime.UtcNow; // 统一获取一次,保证所有实体时间一致 if (_columnSetters.TryGetValue(model.ColumnName, out var setTimeAction)) { foreach (var entity in queriedContext) { setTimeAction(entity, utcNow); } // 记得调用SaveChanges()提交修改(如果用EF的话) }
这种方式用编译好的委托,性能比反射高,代码简洁,维护成本低。
方法二:反射映射(适合列非常多的场景)
如果你的列特别多,不想手动写每个委托,可以用反射动态获取属性并赋值:
// 提前缓存属性信息,避免每次反射查找 private static readonly Dictionary<string, PropertyInfo> _columnPropertyMap = new() { { "DataA", typeof(YourEntityType).GetProperty(nameof(YourEntityType.DataA)) }, { "DataB", typeof(YourEntityType).GetProperty(nameof(YourEntityType.DataB)) }, { "DataC", typeof(YourEntityType).GetProperty(nameof(YourEntityType.DataC)) } }; // 处理请求时的代码 var utcNow = DateTime.UtcNow; if (_columnPropertyMap.TryGetValue(model.ColumnName, out var targetProperty)) { foreach (var entity in queriedContext) { targetProperty.SetValue(entity, utcNow); } // 提交修改 }
注意:反射性能比委托稍差,但如果不是高频调用,差异可以忽略。
方法三:EF Core批量更新(无需加载实体,性能最优)
如果你用的是EF Core 7及以上版本,可以用ExecuteUpdate直接生成SQL更新语句,不需要把实体加载到内存,性能大幅提升:
var utcNow = DateTime.UtcNow; var targetColumn = model.ColumnName; // 构建批量更新操作 var updateOperation = targetColumn switch { "DataA" => _dbContext.YourEntities .Where(e => model.IdList.Contains(e.Id)) .ExecuteUpdate(s => s.SetProperty(e => e.DataA, utcNow)), "DataB" => _dbContext.YourEntities .Where(e => model.IdList.Contains(e.Id)) .ExecuteUpdate(s => s.SetProperty(e => e.DataB, utcNow)), "DataC" => _dbContext.YourEntities .Where(e => model.IdList.Contains(e.Id)) .ExecuteUpdate(s => s.SetProperty(e => e.DataC, utcNow)), _ => null }; // 执行更新 updateOperation?.Execute();
如果想彻底去掉switch,可以用表达式树动态构建SetProperty的表达式,不过实现稍复杂,一般场景下上面的写法已经足够简洁。
内容的提问来源于stack exchange,提问作者TryHard
相关产品推荐
相关产品推荐

