C#中使用JsonPatchDocument.ApplyTo后如何更新Oracle数据库?
获取JsonPatch实体变更,实现Oracle针对性更新
方法1:直接读取JsonPatch的操作记录
JsonPatchDocument本身自带Operations集合,里面存着客户端发过来的所有Patch操作细节——比如是替换(Replace)还是新增(Add)操作,目标属性路径是什么,新值是啥。你直接遍历这个集合就能拿到变更信息:
[HttpPatch, Route("api/serversTarget/{id}")] public IHttpActionResult updateEntity(int id, [FromBody] JsonPatchDocument<ServerTarget> patchEntity) { var entity = db.getAllServers().FirstOrDefault(s => s.id == id); if (entity == null) { return NotFound(); } // 提取变更的字段和值 var changes = new Dictionary<string, object>(); foreach (var op in patchEntity.Operations) { // 路径格式一般是"/属性名",去掉开头的斜杠拿到属性名 var propName = op.Path.TrimStart('/'); // 日常更新主要处理Replace操作,其他类型按需添加 if (op.OperationType == OperationType.Replace) { changes[propName] = op.Value; } } patchEntity.ApplyTo(entity); // 把变更集合传给数据库更新方法 db.updateServerInDatabase(entity, changes); return Ok(entity); }
然后修改你的updateServerInDatabase方法,根据变更集合生成只更新变化字段的SQL,避免全字段更新:
public void updateServerInDatabase(ServerTarget entity, Dictionary<string, object> changes) { if (changes.Count == 0) return; // 拼接SET子句,比如"Name = :Name, IpAddress = :IpAddress" var setClauses = string.Join(", ", changes.Select(kv => $"{kv.Key} = :{kv.Key}")); var sql = $"UPDATE servers_target SET {setClauses} WHERE id = :Id"; using (var cmd = new OracleCommand(sql, yourOracleConnection)) { // 绑定主键参数 cmd.Parameters.Add(":Id", OracleDbType.Int32).Value = entity.id; // 绑定所有变更字段的参数 foreach (var kv in changes) { cmd.Parameters.Add($":{kv.Key}", GetOracleDbType(kv.Value.GetType())).Value = kv.Value; } cmd.ExecuteNonQuery(); } } // 辅助方法:把.NET类型转成对应的OracleDbType private OracleDbType GetOracleDbType(Type type) { if (type == typeof(int)) return OracleDbType.Int32; if (type == typeof(string)) return OracleDbType.Varchar2; if (type == typeof(DateTime)) return OracleDbType.Date; // 按你的实体属性类型补充其他映射 return OracleDbType.Varchar2; }
方法2:对比实体变更前后的快照
如果怕Patch操作有隐式变更(比如某些属性在ApplyTo后被自动修改),可以先给实体拍个快照,ApplyTo之后对比快照和当前实体的差异:
[HttpPatch, Route("api/serversTarget/{id}")] public IHttpActionResult updateEntity(int id, [FromBody] JsonPatchDocument<ServerTarget> patchEntity) { var entity = db.getAllServers().FirstOrDefault(s => s.id == id); if (entity == null) { return NotFound(); } // 创建原实体的快照——手动复制属性或者用AutoMapper都行 var originalEntity = new ServerTarget { id = entity.id, Name = entity.Name, IpAddress = entity.IpAddress, // 把所有需要监控的属性都复制一遍 }; patchEntity.ApplyTo(entity); // 反射对比属性值,找出变更的字段 var changes = new Dictionary<string, object>(); var props = typeof(ServerTarget).GetProperties(BindingFlags.Public | BindingFlags.Instance); foreach (var prop in props) { var originalVal = prop.GetValue(originalEntity); var currentVal = prop.GetValue(entity); if (!Equals(originalVal, currentVal)) { changes[prop.Name] = currentVal; } } // 针对性更新数据库 db.updateServerInDatabase(entity, changes); return Ok(entity); }
注意点
- 值类型(int、DateTime这类)直接对比就行,要是实体有嵌套的引用类型,手动复制快照得处理好深拷贝。
- 要是用EF这类ORM,本来可以靠自带的变更追踪,但你这里是自己维护内存列表,就得手动搞对比。
内容的提问来源于stack exchange,提问作者b.tchman
相关产品推荐
相关产品推荐

