You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 01:01:08