ef使用json类型无法触发更新排查
一.问题背景
首先诸位请看以上代码,不知道有没有发现什么问题?
3
2
1
集成流的配置,目前是使用json结构,保存到数据库中的。当初加这个的时候就有发现,没有写update不更新,但是当初因为一些原因,没有主动去深究这个问题,而是手动补了一行update去触发更新。这几天在调整集成流配置结构的时候,发现了之前写的这个代码,并深究了一下原因。
二.问题定位
首先可以来看一下另一段代码,同样的场景,类似的结构,但是上面这段代码可以触发ef的更新,同学们,发动你们聪明的小脑瓜,有没有想到为什么?这里与异常代码的区别是这里的steps重新赋了个值,基于以上现象,我们推测是因为异常代码只是替换了json内部数据,但是没有更改引用类型的引用地址,导致ef的跟踪器没有触发跟踪。基于以上猜测,我们去翻阅到了一些资料
综上所述,确实是由于我们使用了json类型,导致部分数据的变更,没有触发跟踪器的跟踪,为此,我们补上了以下代码
首先我们实现了了一个值比较器,使用json的md5去校验值是否变更
public class GenericComparer<T> : ValueComparer<T> where T:new() { public GenericComparer() : base((s, t) => Equal(s, t), CreateDefaultHashCodeExpression(false), c => SnapShot(c)) { } public static bool Equal(T? s, T? t) { if (s == null || t == null) { return false; } return s.ToJsonInDb().ToMd5() == t.ToJsonInDb().ToMd5(); } public static T SnapShot(T c) { if (c is null) { return new(); } return c.Adapt<T>(); } }
然后在数据库上下文配置中加上了以下配置
添加了这两段代码之后,ef上下文即可检测到值的变更,进而跟踪数据,生成正确的sql语句。
await Repository.Respositiy<BAS_FlowConfig>().UpdateAsync(flowConfig);
另外我们再来看看由主动触发更新,生成的ef更新语句,这里的更新是会更新整行数据的所有字段,而正常由ef跟踪形成的sql,是只更新修改过的字段,所以减少主动更新的使用,可以提高一部分性能。
三.结论
- 复杂类型的数据,需要自己定义值比较器,否则引用地址不变,ef无法正确获取值的变更
- 主动update会更新整行数据所有字段,由ef跟踪形成的sql,只更新修改过的字段,减少主动更新的使用,可以提高一部分性能。
四.参考文档
https://learn.microsoft.com/zh-cn/ef/core/modeling/value-comparers?tabs=ef5
请原谅我的痴心妄想,我只是个有情怀的程序员;
请约束你的躁动不安,我也是个有礼貌的程序员。