我们有使用 JPA 1.0 和 JAX-WS 的最简单的 CRUD 任务。
假设我们有一个实体 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 服务请求以创建人员。在服务器端,一切都很简单。
它确实按预期工作。
@Stateless
@WebService
public class PersonService
{
@PersistenceContext(name = "unit-name")
private EntityManager entityManager;
public Person create(Person person)
{
entityManager.persist(person);
return person;
}
}
现在客户端尝试更新人员,这就是对我而言,JPA 显示其不一致的地方。
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 并在合并之前做这样的事情。
Person existingPerson = entityManager.find(Person.class, person.getEmail());
person.setReadOnlyObject(existingPerson.getReadOnlyObject()); // Arghhh!
我的问题:
不一致?
你)处理这种情况?请
不要建议我使用 DTO。
最佳答案
Is it a feature or just inconsistence?
我不知道,但我想说这是
merge
的预期行为.以下是对实体调用合并时发生的情况:这适用于简单的情况,但如果您收到一个部分值的对象(某些字段或关联设置为
null
)到 merge
则不行。 : 数据库中的空字段将设置为空,这可能不是您想要的。How do you (or would you) handle such situations? Please don't advice me to use DTOs.
在这种情况下,您应该使用“手动合并”:使用
find
加载现有实体并通过复制新状态来更新自己要更新的字段,让 JPA 检测更改并将它们刷新到数据库中。
关于JPA 合并只读字段,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3228304/