JPA merge read-only fields

We have the simplest crud tasks, including JPA 1.0 and jax-ws

@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
}

This is the scene The client creates a web service request to create a person On the server side, everything is simple It did 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;
   }
}

Now the client tries to update the staff, which is where I, JPA, show its inconsistency

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;
}

To avoid this problem, I need to expose the set for the readonly object and perform similar operations before merging

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

My question:

>Is this a function or just inconsistent? > how are you? You) deal with this situation? Please do not suggest that I use dto

Solution

I don't know, but I would say this is the expected behavior of the merger The following is what happens when you call merge on an entity:

>Existing entities load in persistence context (if not already present) > copy state from object to merge into loaded entity > changes made to loaded entity will be saved to database on refresh > return loaded entity

This applies to simple cases, but if you receive a partial value object (some fields or associations are set to null) to merge, it will not work properly: the empty fields in the database will be set to null, which may not be what you want

In this case, you should use "manual merge": use find to load existing entities and update the fields to be updated by copying the new state, so that JPA can detect the changes and refresh them to the database

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>