如何使用Spring MVC忽略DTO对象中缺少的属性?

时间:2015-01-27 20:03:07

标签: java hibernate spring-mvc dto

我们正在使用Spring MVC 4

假设我有一个名为Customer的实体。该实体有几个属性,有些允许空值,有些则不允许。

我们还使用从远程客户端通过DTO传递到CustomerDTO的{​​{1}}对象(@RestController)。

这是我遇到的问题。假设用户通过@RequestBody

传递以下内容
PUT

一切都很好。但是,如果用户只想更新{ "id": 123, "name": "ACME", "desc": "Blah" } ,则会传入:

name

客户现在{ "id": 123, "name": "ACME 2" } 中有一个允许的null

所以我的问题是,如果没有将desc放入更新语句中,如果它没有传递给DTO,我怎么能让Spring / Hibernate?

我认为,问题在于Spring将以下内容视为同一件事:

desc

由于

2 个答案:

答案 0 :(得分:0)

根据Is it possible to update only a subset of attributes on an entity using Spring MVC with JPA?,您似乎基本上有两个可行的选项:

  1. 从数据库中读取实体并更新特定字段
  2. 使用@SessionAttibutes

答案 1 :(得分:0)

您可以使用Blaze-Persistence Updatable Entity Views来代替通过分别加载实体状态来实现此目的,它是在JPA之上用于开发DTO的库,该库还实现了对乐观锁定的支持。 您的用例应该已经得到支持,尽管我还没有与Spring WebMvc很好的集成,所以您现在必须自己做一些工作。不过,我有一些想法,在整合变得更加顺利之前,这只是时间问题和感兴趣的参与者。

可更新的实体视图允许映射实体的子集,并且也只能刷新该子集。由于使用了脏跟踪,它可以准确地知道发生了什么变化,从而可以进行细粒度的冲洗。

因此,您要在此处获得 PATCH支持的想法是,仅通过id获得对象的空引用。为空表示没有数据,即所有空值。脏跟踪假定初始状态全为空。您可以简单地将请求有效负载映射到该对象,如果值为null,则不会将其识别为已更改,因此将其忽略。如果设置了任何非空值,它将确定该字段是脏的,并且在刷新时仅刷新脏值。

我还没有尝试过,但是您可以做类似的事情

// Create reference for the id, the object is empty i.e. all null except for the id
CustomerDTO dto = entityViewManager.getReference(CustomerDTO.class, someId);
// Map the payload on the DTO which will call setFoo(null) but that's ok, because that isn't considered being dirty
jsonMapper.map(requestPayload, dto);
// Flush dirty changes i.e. non-null values
entityViewManager.update(entityManager, dto);

在使用PARTIAL刷新模式时执行的更新查询将仅包含具有非空值的属性的set子句。 DTO看起来像这样

@EntityView(Customer.class)
@UpdatableEntityView(mode = FlushMode.PARTIAL)
public interface CustomerDTO {
  @IdMapping Integer getId();
  String getName();
  void setName(String name);
  String getDesc();
  void setDesc(String desc);
}

如果没有脏东西,它甚至不会执行查询。