我使用Spring数据jpa进行持久化。 说,我必须更新模型。 这个模型有' n'字段数和主键。
{
"some_model":{
"id":"5527716",
"field_one": "44248156",
"field_two": "44248156",
"field_three": "44248156",
"field_four": "44248156",
"field_five": "44248156",
"field_six": "44248156",
"field_seven": "44248156",
"field_eight": "44248156",
"field_nine":"65037768"
}
}
考虑到上面的json作为我的模型的表示,我想只更新那些在json中传入的字段(主键是Id,它总是在那里)。有没有什么方法可以实现,而无需明确检查每个字段并设置它们?
说我收到的请求如下:
{
"some_model":{
"id":"5527716",
"field_one": "44248156",
"field_two": "44248156",
"field_three": "44248156",
"field_eight": "44248156",
"field_nine":"65037768"
}
}
我想使用repository.save或类似的东西来实现更新(upsert类的东西)。目前,使用存储库的保存方法在内部使用primaryKey值更新模型,但将缺少字段的值设置为null。我希望这些字段保持不变。
主要问题是:有数百个模型,每个模型有大约10-15个字段,并明确检查每个字段,所有模型的更新将是一场噩梦。
我还检查了@DynamicUpdate
注释,但它似乎适用于优化生成的sql的显式设置。
我很感激有关此事的任何想法。
答案 0 :(得分:2)
通常合并将对您有用,因为您有分离的副本 - 您从JSON获得的副本和持久的副本(来自存储库)。 Merge正是这样做 - 用分离的值更新持久化属性,如果没有,则创建它(我不确定该部分是否可取)。仍然使它自动化你会失去自己编写的灵活性。
使用JPA,merge方法是EntityManager的一部分。所以你需要注入它并像em.merge(detachedEntity);
一样调用它除此之外还有图书馆可以做到,但我还没有使用过。而需要编码的最佳解决方案是编写一种手动更新字段的方法;)
答案 1 :(得分:0)
看看dozer - 一个bean映射库。您可以使用自定义字段映射器配置dozer,以便在字段为空时不复制该字段。
您可以从数据库中检索对象,将字段值从请求对象复制到从DB检索的对象(使用不映射空值的自定义字段映射器),然后保存对象。
User user1 = new User(); // Request body
user1.setFirstName("newFn");
User user2 = new User(); // Entity retrieved from the database
user2.setFirstName("fn");
user2.setLastName("ln");
DozerBeanMapper dozerBeanMapper = new DozerBeanMapper();
dozerBeanMapper.setCustomFieldMapper(
(source, destination, sourceFieldValue, classMap, fieldMapping) -> sourceFieldValue == null);
dozerBeanMapper.map(user1, user2);
System.out.println(user2); // User(firstName=newFn, lastName=ln)
参考:https://stackoverflow.com/a/36716023/1377058
如果您不想将dozer添加为依赖项,则还可以使用BeanUtils仅复制那些非null的属性。请查看this问题,了解有关如何操作的详细信息。
答案 2 :(得分:0)
我发现我的问题的确切要求无法满足。 Dozer Bean Mapper似乎是一个选择,但更多的是关于映射不同类的Bean对象,在这里我们可以对应要映射的字段,这不是我的情况。
解决方案是更改在更新时发送所有必需信息的方法。
Simon在评论中指出:
简单答案:不可能。因为反序列化后 字段缺失,值为空。 Java是一种静态类型语言 不能很好地满足您的要求。