2010-01-16 74 views
13

我正在觀察一個非常奇怪的行爲與一個實體類,並加載該類與JPA(hibernate entitymanager 3.3.1.ga)的對象。該類有一個(嵌入)字段,該字段在聲明中初始化。該領域的設置者實現一個空檢查(即當設置一個空值時會引發一個異常)。奇怪的JPA行爲,初始化字段爲空

... 
@Entity 
public class Participant extends BaseEntity implements Comparable<Participant> { 
    ... 
    @Embedded 
private AmsData amsData = new AmsData(); 

public void setAmsData(AmsData amsData) { 
    Checks.verifyArgNotNull(amsData, "amsdata"); 
    this.amsData = amsData; 
} 
    ... 
} 

當我使用JPA這個目的,本字段爲空,如果在數據庫中嵌入對象指定的字段沒有數據。

... 
public class ParticipantJpaDao implements ParticipantDao { 
@PersistenceContext 
private EntityManager em; 

@Override 
public Participant getParticipant(Long id) { 
    return em.find(Participant.class, id); 
} 
    ... 
} 

我調試的進程與該領域的觀察點(應該停止時域被訪問或修改),和我看的時候字段被初始化一個修改,但是當我從查找調用的結果,該字段爲空。

有人可以解釋一下,爲什麼這樣呢?如何確保字段不爲空,並且在db中沒有嵌入對象字段的數據時(除了在查找調用後手動設置數據)。

+0

可能這是由於您的持久化引擎延遲加載的關聯? – 2010-01-16 08:08:53

+0

我確實使用延遲加載,但這是一個嵌入字段,因此存儲在同一個表中。是否有可能對此進行註釋以獲取熱切? – Dominik 2010-01-16 08:15:17

+0

相關的Hibernate問題(取自已刪除的答案):[HHH-7610:當所有列都爲NULL時將@Embedded字段設置爲空的選項](https://hibernate.atlassian.net/browse/HHH-7610) – sleske 2015-01-30 16:00:25

回答

16

JPA規範沒有明確說明如何處理一組表示可嵌入對象的列,這些列都是空的。它可以表示一個空引用,或者一個帶有全空字段的對象實例。在這種情況下,Hibernate選擇一個空引用,但其他JPA實現可能會選擇後者。

您的setter從未被調用的原因是因爲Hibernate正在通過反射訪問您的字段,繞過了您實現的setter。這是因爲您使用基於字段的訪問而不是基於屬性的訪問。

乍得的答案將提供您正在尋找的功能,但有一個警告(見下文)。

」 ...的實體 的持久狀態由持久性 提供商運行時訪問[1]或者通過 JavaBeans風格屬性訪問或通過實例變量 。單個 訪問類型(字段或屬性訪問) 適用於實體的層次結構。當使用 註解,的 放置在任一 持久字段或實體類 的持久 屬性映射註解指定訪問類型爲 任一現場ö [R財產爲基礎分別訪問 ......」 [EJB3持久 規格]

所以通過移動註釋下到二傳手,你告訴JPA要使用基於屬性的訪問,而不是現場基於訪問。但是,您應該知道,基於字段的訪問(正如您當前實施的那樣)優於基於屬性的訪問。基於屬性的訪問不鼓勵,有兩個原因,一個是他們你不得不爲所有持久化實體字段添加getter和setter,但是你可能不希望那些相同的字段容易受到外部客戶端的變異影響。換句話說,使用JPA的基於屬性的訪問會迫使你削弱實體的封裝。

+0

但爲什麼會它將該字段設置爲空? – Dominik 2010-01-16 08:16:54

+0

我更新了答案,以解釋爲什麼該字段可能爲空。最常見的原因是你的數據庫中有記錄,這些記錄早於添加** amsData **字段。 – rcampbell 2010-01-16 08:31:05

+0

我只是用一個非null(但是爲空)的AmsData對象存儲了一個新的實體,我又得到了相同的結果。是的,AmsData類是註釋可嵌入的。 – Dominik 2010-01-16 08:49:31

1

那麼,你的對象可能會在幕後進行兩次構建。 JPA實現通常會直接設置這些字段。

我想你需要把註釋放在Getters和setter自己上,如果你想讓它們被使用的話。看到這個答案:

Empty constructors and setters on JPA Entites

+0

嵌入式對象也只有列且沒有關聯,可以提取渴望。 – Dominik 2010-01-16 08:30:23

3

答案是(感謝rcampell),如果嵌入對象的所有數據爲空(在分貝),嵌入的對象也將是無效的,但是當它被初始化在宣言中。唯一的解決方案似乎是手動設置對象。

@Override 
public Participant getParticipant(Long id) { 
    Participant participant = em.find(Participant.class, id); 
    if(participant != null && participant.getAmsData() == null) 
    { 
     participant.setAmsData(new AmsData()); 
    } 
    return participant; 
} 

仍然覺得很奇怪,我...

+0

幾周前有同樣的問題。這將做到這一點。 +1 – whiskeysierra 2010-01-24 16:35:40

+0

該解決方案觸發數據庫服務器的sql更新指令,帶來線程間併發性和性能問題等問題。 – 2015-03-05 03:23:19