Java jOOQ中处理REST API PATCH请求时优雅排除空值更新的方案咨询
Java jOOQ中处理REST API PATCH请求时优雅排除空值更新的方案咨询
当然有更优雅的写法!你现在的思路没问题,但字段多了确实会写一堆重复的if判断,太繁琐了。我来给你分享几个jOOQ里常用的简化方案:
方案1:利用jOOQ对Optional的原生支持(jOOQ 3.14+)
jOOQ从3.14版本开始,UpdateSetStep的set方法原生支持传入Optional参数——当Optional为空时,这个字段的更新操作会被自动跳过。你可以把请求里的每个字段都包装成Optional,然后链式调用set就行,完全不用手动写if判断:
public BankResponse update(BankUpdateRequest request, Integer id) { var update = dsl.update(BANK) .set(BANK.NAME, Optional.ofNullable(request.naziv())) .set(BANK.BANK_ACCOUNT, Optional.ofNullable(request.ziroRacun())) .set(BANK.FAX, Optional.ofNullable(request.fax())); // 检查是否有实际要更新的字段 if (update.getQuery().getUpdateSets().isEmpty()) { throw new IllegalStateException("No fields to update"); } return update .where(BANK.ID.eq(id)) .returning() .fetchOptional() .map(r -> r.into(BankResponse.class)) .orElseThrow(() -> new ResourceNotFoundException(EntityType.BANK, id)); }
这样写每个字段只需要一行,逻辑清晰多了,字段再多也不怕。
方案2:用Record的变更跟踪特性自动过滤空值
如果你习惯用jOOQ的Record对象来处理,可以先创建一个空的BankRecord,只把请求里的非空值设置进去,然后利用jOOQ自带的变更跟踪(默认开启),让它自动只更新被修改过的字段:
public BankResponse update(BankUpdateRequest request, Integer id) { BankRecord record = dsl.newRecord(BANK); // 只设置非空的字段 Optional.ofNullable(request.naziv()).ifPresent(record::setName); Optional.ofNullable(request.ziroRacun()).ifPresent(record::setBankAccount); Optional.ofNullable(request.fax()).ifPresent(record::setFax); // 检查是否有字段被修改 if (!record.isChanged()) { throw new IllegalStateException("No fields to update"); } return dsl.update(BANK) .set(record) // jOOQ会自动只更新被标记为"已修改"的字段 .where(BANK.ID.eq(id)) .returning() .fetchOptional() .map(r -> r.into(BankResponse.class)) .orElseThrow(() -> new ResourceNotFoundException(EntityType.BANK, id)); }
这种方式更贴近jOOQ的ORM风格,isChanged()方法能直接帮你判断有没有需要更新的内容,不用自己维护moreStep变量。
方案3:动态构建更新步骤(适合大量字段的场景)
如果你的实体有几十个字段,不想一个个写set语句,可以把所有要处理的字段和对应的请求值做成一个集合,然后通过Stream过滤掉空值,动态累积更新步骤:
public BankResponse update(BankUpdateRequest request, Integer id) { UpdateSetStep<BankRecord> baseUpdate = dsl.update(BANK); // 把所有要处理的字段和对应请求值配对 List<Map.Entry<Field<?>, Object>> fieldsToUpdate = Arrays.asList( new AbstractMap.SimpleEntry<>(BANK.NAME, request.naziv()), new AbstractMap.SimpleEntry<>(BANK.BANK_ACCOUNT, request.ziroRacun()), new AbstractMap.SimpleEntry<>(BANK.FAX, request.fax()) // 其他字段继续往下加就行 ); // 过滤掉值为null的条目,累积到更新步骤中 UpdateSetMoreStep<BankRecord> finalUpdate = fieldsToUpdate.stream() .filter(entry -> entry.getValue() != null) .reduce(baseUpdate, (currentStep, entry) -> currentStep.set(entry.getKey(), entry.getValue()), (step1, step2) -> step1); // 判断是否有实际要更新的字段 if (finalUpdate == baseUpdate) { throw new IllegalStateException("No fields to update"); } return finalUpdate .where(BANK.ID.eq(id)) .returning() .fetchOptional() .map(r -> r.into(BankResponse.class)) .orElseThrow(() -> new ResourceNotFoundException(EntityType.BANK, id)); }
这种方式的好处是字段再多,只需要在fieldsToUpdate里加条目就行,不用修改核心逻辑代码,维护起来特别方便。
这几个方案都能帮你摆脱繁琐的if嵌套,选哪种主要看你的代码风格和项目使用的jOOQ版本。我个人最常用方案1,简洁又符合jOOQ的设计思路。
备注:内容来源于stack exchange,提问作者aleks
相关产品推荐
相关产品推荐

