JPA合并只读字段 [英] JPA merge readonly fields

查看:229
本文介绍了JPA合并只读字段的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有最简单的CRUD任务,包括JPA 1.0和JAX-WS。

假设我们有一个实体Person。

We have the simplest CRUD task with JPA 1.0 and JAX-WS.
Let's say we have an entity Person.

@Entity
public class Person
{
   @Id
   private String email;

   @OneToOne(fetch = FetchType.LAZY)
   @JoinColumn(insertable = false, updatable = false)
   private ReadOnly readOnly;

   @Column
   private String name;      

   @XmlElement
   public String getEmail()
   {
      return email;
   }

   public void setEmail(String email)
   {
      this.email = email;
   }

   @XmlElement
   public Long getReadOnlyValue()
   {
      return readOnly.getValue();
   }

   // more get and set methods
}

这是一个场景。
客户端创建Web服务请求以创建人员。在服务器端,一切都很简单。
它确实按预期工作。

Here is scenario. Client make Web Service request to create person. On the server side everything is straightforward. And it does work as expected.

@Stateless
@WebService
public class PersonService
{
   @PersistenceContext(name = "unit-name")
   private EntityManager entityManager;

   public Person create(Person person)
   {
      entityManager.persist(person);

      return person;
   }
}

现在客户端尝试更新人员,这就是对我来说,JPA显示其不一致。

Now client tries to update person and this is where, as for me, JPA shows its inconsistence.

public Person update(Person person)
{
   Person existingPerson = entityManager.find(Person.class, person.getEmail());

   // some logic with existingPerson
   // ...      

   // At this point existingPerson.readOnly is not null and it can't be null
   // due to the database.
   // The field is not updatable.
   // Person object has readOnly field equal to null as it was not passed 
   // via SOAP request.
   // And now we do merge.

   entityManager.merge(person);

   // At this point existingPerson.getReadOnlyValue() 
   // will throw NullPointerException. 
   // And it throws during marshalling.
   // It is because now existingPerson.readOnly == person.readOnly and thus null.
   // But it won't affect database anyhow because of (updatable = false)

   return existingPerson;
}

为了避免这个问题,我需要为readOnly对象公开set并执行类似的操作在合并之前。

To avoid this problem I need to expose set for readOnly object and do something like this before merge.

Person existingPerson = entityManager.find(Person.class, person.getEmail());
person.setReadOnlyObject(existingPerson.getReadOnlyObject()); // Arghhh!

我的问题:


  • 这是一个功能还是只是
    不一致?

  • 你如何处理这种情况(或b
    )?请
    不建议我使用DTO。

推荐答案


是功能还是仅仅是不一致?

Is it a feature or just inconsistence?

我不知道,但我会说这是 merge 。以下是在实体上调用合并时发生的情况:

I don't know but I'd say that this is the expected behavior with merge. Here is what is happening when calling merge on a entity:


  • 现有实体在持久化上下文中加载(如果尚未存在)

  • 将状态从对象复制到合并到已加载的实体

  • 对已加载实体所做的更改将在刷新时保存到数据库中

  • 返回已加载的实体

  • the existing entity gets loaded in the persistence context (if not already there)
  • the state is copied from object to merge to the loaded entity
  • the changes made to the loaded entity are saved to the database upon flush
  • the loaded entity is returned

这种方法在简单的情况下工作正常,但如果收到部分值对象(某些字段或关联设置为 null )到 merge :空字段将设置为null在数据库中,这可能不是你想要的。

This works fine with simple case but doesn't if you receive a partially valued object (with some fields or association set to null) to merge: the null fields will be set to null in the database, this might not be what you want.


你(或者你)如何处理这种情况?请不要建议我使用DTO。

How do you (or would you) handle such situations? Please don't advice me to use DTOs.

在这种情况下,您应该使用手动合并:加载现有实体使用 find 并通过复制新状态自行更新要更新的字段,让JPA检测更改并将其刷新到数据库。

In that case, you should use a "manual merge": load the existing entity using find and update yourself the fields you want to update by copying the new state and let JPA detect the changes and flush them to the database.

这篇关于JPA合并只读字段的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆