JAX-RS + JPA,如何仅更新/合并实体字段的子集?

时间:2016-03-10 17:35:07

标签: json jpa jax-rs

假设我有以下实体:

@Entity
@XmlRootElement
@XmlAccessorType( XmlAccessType.FIELD)
public class MyEntity {

    @Id
    @GeneratedValue
    private long id;

    private boolean field1;

    private boolean field2;

    private boolean field3;
}

假设我有一个REST Web服务,允许客户端对MyEntity资源进行部分或完整更新。也许方法签名看起来像这样:

@POST
@Path("{id}")
public Response postMyEntity(@PathParam("id") long id, MyEntity myEntity)

以下是客户端可能仅使用ID 101更新MyEntity的“field2”的JSON:

{
    "id": 101
    "field2": true
}

如果JPA知道在反序列化过程中只设置了field2,那么我很乐意使用以下代码来保持此更改:

entityManager.merge(myEntity);

但是,此操作会更新field1,field2和field3。

人们通常如何确保只在数据库中更新REST请求中JSON / XML中明确指定的字段?我已经读过在他们的Web服务中使用DTO的人(而不是实体本身),并且手动确定需要在相应的实体上设置哪些字段...但是,这个用例似乎很常见,我很惊讶这需要DIY方法。

1 个答案:

答案 0 :(得分:1)

也许有更好的解决方案,但我决定强制我的REST服务生成和使用DTO而不是实体。我的DTO类从不使用原语(Integer而不是int),这确保了如果客户端省略了JSON / XML属性,那么相应的DTO字段将为null。

当我收到POST以更新资源时:

  1. 从数据库中获取相应的实体。
  2. 将所有非空字段从DTO复制到实体。
  3. 使用JPA的合并功能更新数据库。
  4. 当我收到资源的GET时我:

    1. 从数据库中获取实体。
    2. 将实体中的所有字段复制到新的DTO。
    3. 将DTO退还给客户。
    4. 设置这个很乏味,因为它要求我:

      1. 创建一组几乎与相应实体类完全相同的DTO类。
      2. 编写逻辑以在DTO和实体之间进行转换。
      3. 继续保持这种混乱。
      4. 我没有使用DTO,而是假设我可以从我的Entity类中删除基元,并为这些字段添加非空约束。但是,我在几个地方读到这是一个“坏主意”#34;将您的Entity类直接公开给REST客户端。所以我继续使用DTO解决方案,尽管我不是它的最大粉丝。