Spring Data JPA:如何优雅地更新模型?

Spring Data JPA: How to update a model elegantly?

  1. 我的模型是这样的:

    @Entity
    @Table(name = "user")
    public class User {
    
        @Id
        @GeneratedValue(strategy = GenerationType.AUTO)
        private Long id;
    
        @Column(name="email")
        private String email;
    
        @Column(name = "weblink")
        private String webLink;
    
        //getter & setter
    }
    
  2. 我们通过http请求收集表单或移动数据,springmvc会将这些数据做成一个Model like user

    例如,我有这样一个请求:

    http://localhost:8080/update?id=1919&email=xx@google.com

  3. 在控制器中,请求url及其参数将自动转换为User对象。

    @RequestMapping(method = RequestMethod.GET, value = "/update0")
    public User update(@ModelAttribute("User") User user){
    
        System.out.println(user.getId());
        System.out.println(user.getEmail());
        System.out.println(user.getWebLink());
    
        return userRepository.save(test);
    }
    
  4. 如果我在mysql中有一条id为1919的记录,并且列(id,email,weblik)都有值。

    如你所见,通过网络或手机传递的用户对象有两个属性

    http://localhost:8080/update?id=1919&email=xx@google.com

    id 和 email 有值而 weblink 没有。

    因此,如果我执行 save 方法,电子邮件列将更新为 xx@google.com,weblik 字段也将更新为 NULL,但我没有想更新这个字段,我只想更新电子邮件字段。

  5. 我有两种方法可以解决这个问题,但都不太优雅。

    5.1 先加载用户对象并更新

    User userExist = userRepository.findOne(user.getId());
    userExist.setEmail(user.getEmail());
    
    //or using 
    //BeanUtil.copyProprty(formDto,modle)
    
    userRepository.save();
    

    5.2 使用 @DynamicUpdate,但它不起作用。

    有没有其他方法可以更新用户模型并且不做一些额外的工作。

    提前致谢。

最简单的方法是适当设置控制器方法:

@RequestMapping(value = "/users/{user}", method = RequestMethod.PATCH)
public … updateUser(@ModelAttribute User user) { … }

根据reference documentation调用此方法时会发生以下步骤:

  1. 需要获取User的实例。这基本上需要从 StringUserConverter 注册到 Spring MVC 以将从 URI 模板中提取的路径段转换为 User。如果你是使用 Spring 数据并启用其 reference documentation 中所述的 Web 支持,这将开箱即用。
  2. 获取现有实例后,请求数据将绑定到现有对象。
  3. 绑定的对象将被传递到方法中。

其他提示

  • 不要使用 GET 作为更新的 HTTP 方法。 GET 被定义为安全操作(无副作用),更新不是。 PATCH 是此处的正确方法,因为它被定义为允许对现有资源进行部分更新。
  • 要将表单数据提交到 PUTPATCH 请求中,您需要按照 here. I filed an issue with Spring Boot 所述向应用程序注册一个 HttpPutFormContentFilter 以默认注册。

首先我要说 @Oliver GierkePatch 解决方案真的很棒。

而在我之前的项目中,我的解决方案是:
1、创建抽象class实现JpaRepository,实现save()功能
2. 在保存函数中,从数据库中获取实体。它不存在,只是保存它。否则,使用反射从更新的实体中获取所有 NOT NULL 字段,并从数据库中设置到实体中。 (和你做的很相似,不过我是为了所有的保存功能而做的)