2010-08-02 127 views
5

我有一個應用程序使用Hibernate的數據持久性,與頂部的彈簧(好措施)。直到最近,有一個持久化類的應用,A:使用DiscriminatorFormula遷移Hibernate數據庫是不好的做法嗎?

@Entity 
public class A { 
    @Id 
    @Column(unique = true, nullable = false, updatable = false) 
    @GeneratedValue(strategy = GenerationType.IDENTITY) 
    private long id; 
    public String name; 
} 

因爲我已經添加了一個子類,稱爲B:

@Entity 
public class B extends A { 
    public String description; 
} 

加入B之後,我現在可以不加載的。拋出以下異常:

class org.springframework.orm.hibernate3.HibernateObjectRetrievalFailureException :: Object with id: 1 was not of the specified subclass: A (Discriminator: null); nested exception is org.hibernate.WrongClassException: Object with id: 1 was not of the specified subclass: A (Discriminator: null) 

我向B添加了以下注釋和屬性,它似乎解決了這個問題。這是解決問題的正確方法嗎?

... 
@DiscriminatorFormula("(CASE WHEN dtype IS NULL THEN 'A' ELSE dtype END)") 
public class A { 
    private String dtype = this.getClass().getSimpleName(); 
    ... 

回答

2

(...)直到最近,有應用中的一個持久化類,A:

用下面的數據庫表示:

ID NAME 
-- ---- 
1 foo 
2 bar 

我已經添加了A的子類,稱爲B(...)

而您沒有指定Inheritance註釋,因此使用SINGLE_TABLE映射策略。和在此策略中,層次結構中的所有類都映射到單個表。該表具有用作「鑑別器列」的列,即,其值用於標識該行表示的實例所屬的特定子類的列。

表則成了:

ID NAME DTYPE 
-- ---- ----- 
1 foo NULL 
2 bar NULL 

哪裏DTYPE是列的默認名稱用於鑑別。

添加B後,我現在可以不加載A了。拋出以下異常(...)

事實上,由於現有值在鑑別器列中具有空值,因此提供者不知道要實例化哪個子類。

我向B添加了下面的註解和屬性,它似乎解決了這個問題。這是解決問題的正確方法嗎?

這是一種方式,但它是侵入性的(您的實體不應該知道dtype列)和Hibernate特定。換句話說,這是一個黑客。

對於我來說,「正確」的方式來解決,這將是更新現有的A記錄的值設置爲'A'(與Hibernate,則默認值爲實體名稱)的DTYPE列:

UPDATE A SET DTYPE='A' WHERE DTYPE=NULL 

這樣,Hibernate就能夠正確加載它們。

+0

感謝您的詳細解答。不幸的是,我不會直接訪問應用程序的所有安裝,所以我希望這種模式更改對用戶透明。我嘗試添加DiscriminatorFormula而沒有明確定義dtype字段,但是這不起作用。當我這樣做的時候感覺像是一個黑客 - 這就是爲什麼我問。 – Armand 2010-08-03 08:48:12

+1

@Alison不客氣。我給你什麼是IMO的「理想」解決方案。如果它不適合你的上下文,如果你不能爲你的用戶提供一個遷移腳本(這將在各種「ALTER」之後執行'UPDATE'),或者甚至是更好的自動遷移工具 - 那麼你的解決方案是可以接受的。至少它工作。而現在你知道它有點破解:) – 2010-08-03 09:19:02

+0

- )我發現在Hibernate/Spring中遷移的信息相當難以處理,不幸的是。 – Armand 2010-08-03 12:40:31

相關問題