2010-07-12 65 views
4

我們使用JPA 1.0和JAX-WS進行最簡單的CRUD任務。
假設我們有一個實體Person。JPA合併只讀字段

@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對象,並在合併之前做這樣的事情。

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

我的問題:

  • 它是一個功能或者只是 不一致?
  • 你(或你會) 你如何處理這種情況?請 不建議我使用DTO。
+0

你有沒有找到一個更好的替代方案來輕鬆使用不可更新的字段? – Kevin 2015-07-31 02:09:03

回答

1

它是一個功能還是隻是不一致?

我不知道,但我會說這是merge的預期行爲。這裏是調用一個實體合併時所發生的事情:

  • 現有實體獲取持久化上下文加載(如果尚未有)
  • 狀態從對象複製到合併所加載的實體
  • 所加載的實體所做的更改保存到在沖洗
  • 加載的實體數據庫返回

這正常工作與簡單的例子,但如果你收到部分價值Ø不bject(有些字段或關聯設置爲null)至merge:null字段將在數據庫中設置爲null,這可能不是您想要的。

你(或你)會如何處理這種情況?請不要建議我使用DTO。

在這種情況下,你應該使用「手動合併」:使用find加載現有的實體,並更新自己,你想通過複製新的狀態更新領域,讓JPA檢測的變化,並將它們刷新到數據庫。

+0

「空字段將被設置爲null在數據庫中」如果我使用'updatable = false'不是這種情況 – 2010-07-12 13:57:08

+0

我有40個字段在實體中,這是不是很好,有40個設置和獲得這樣的調用簡單的任務。 – 2010-07-12 13:58:06

+0

@Mykola事實上,如果你使用「updatable = false」,情況並非如此。但是,我的觀點是要麼使用合併(並返回合併的實例)要麼是「手動合併」。你目前的方法看起來很奇怪。 – 2010-07-12 15:18:17