如何使用spring数据jpa仅更新模型中的传入字段?

时间:2018-05-30 12:25:36

标签: java spring hibernate spring-boot spring-data-jpa

我使用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的显式设置。

我很感激有关此事的任何想法。

3 个答案:

答案 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是一种静态类型语言   不能很好地满足您的要求。