代码之家  ›  专栏  ›  技术社区  ›  Sudip Bhandari

如何使用spring data jpa只更新模型中的传入字段?

  •  4
  • Sudip Bhandari  · 技术社区  · 6 年前

    我使用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之类的东西)。当前使用repository的save方法在内部使用primarykey值更新模型,但将缺少字段的值设置为空。我希望这些字段保持不变。

    主要问题是:有数百个模型,每个模型有大约10-15个字段,显式地检查每个字段并更新所有模型将是一场噩梦。

    我也查过了 @DynamicUpdate 注释,但它似乎适用于显式设置,其中生成的sql是优化的。

    我希望你对此有任何想法。

    3 回复  |  直到 6 年前
        1
  •  2
  •   Veselin Davidov    6 年前

    通常,合并会为您工作,因为您得到了分离的副本-一个从json获得的副本,一个持久的副本(来自存储库)。merge确实做到了这一点-用分离的属性的值更新持久化属性,如果没有则创建它(我不确定该部分是否值得)。仍然让它自动化,你就失去了你自己写它的灵活性。

    对于jpa,merge方法是entitymanager的一部分。所以你需要注入它并像em.merge(detachedEntity)那样调用它;

    除此之外,还有一些图书馆可以这样做,但我没有用过。最好的解决方案是编写一个方法来手动更新字段;)

        2
  •  0
  •   Ranjith    6 年前

    看一看 dozer -一个bean映射库。可以使用自定义字段映射器配置dozer,使其在字段为空时不复制该字段。

    可以从数据库检索对象,将请求对象中的字段值复制到从数据库检索的对象(使用不映射空值的自定义字段映射器),然后保存对象。

        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只复制那些不为空的属性。看一看 this 询问如何做的细节。

        3
  •  0
  •   Sudip Bhandari    6 年前

    我发现我的问题的确切要求无法满足。 Dozer Bean Mapper 似乎是一个选项,但更多的是关于映射不同类的be an对象,在这里我们可以对应要映射的字段,这不是我的情况。

    解决方案是改变在执行更新时发送所有必需信息的方法。

    AS Simon 评论中指出:

    简单回答:那是不可能的。因为在反序列化之后 字段缺少值为空。Java是一种静态类型语言 不太符合你的要求。