2009-10-21 19 views
1

我想用其標識符來保存其他實體的引用。在Hibernate中使用實體ID作爲參考

我工作的對象模型非常龐大,相關實體擁有大量數據。還有幾件是循環的,我懷疑直接拿着物品會成爲一個問題。

所以考慮以下作爲一個例子說,有兩個實體一個& B:

Class A 
{ 
private String id; 
private String name; 
private String type; 
private String b_id // A reference to instance of B without holding direct instance 
} 

Class B 
{ 
private String id; 
private String name; 
private String type; 
} 

如何做到這一點使用Hibernate框架?

回答

3

你寫的有兩個不同的類,它們之間沒有任何關係,這就是Hibernate將如何處理它們。

當您從Hibernate讀取A的實例時,您將不得不返回Hibernate來請求B的實例,該實例對應於Ab_id

我強烈建議您使用普通的對象引用並給Hibernate機會來完成它的工作。不要提前寫下它,因爲你認爲它不會應付。

1

你基本上忽略了ORM可以給你的力量。

請記住,a.getB()。getId()將而不是初始化B實例!只有當你實際訪問B的其他方法和屬性(或者你明確地查詢它)時,像Hibernate這樣的(良好)ORM纔會真正打擾取回B.

+0

是但我需要經由SOAP運送這些對象到客戶端,以便客戶端需要有一種方法,其中將約聯繫實體即乙進一步的信息可以,所以我需要要麼提供一個裁判B(其是指具有另一查詢用於SOAP通信的對象模型)或'完整'對象A即對象A的所有字段加上'完整'對象B – Chetan 2009-10-21 10:38:02

+0

聽起來就像你需要一個DAO(Dataaccess對象)。 無論是休眠還是別的什麼能夠持久對象,而無需對實例的引用...你總是可以有兩個映射一類 - 一個RealA和partialA一個正確映射和對方只是作爲純粹的價值。您可以使用entity-name爲同一個類使用多個映射。 – 2009-10-25 19:09:04

0

謝謝你的回答。幾件事情我想指出,

  • A類& B的關係,但我知道的信息告訴Hibernate關係的唯一方法是通過使用正常的對象引用。我想知道是否可以在class Aclass B之間以任何方式關聯,而不必將B的實例保留在A中。我可以在對象模型有B的ID在A然而,在數據庫已B_ID作爲外鍵B --> A

  • 我肯定會像Hibernate照顧的情況,但裁判鏈的深度,以至於查詢由於直接實例成員,一個對象會導致大量信息流過。所以我認爲避免這種情況的一種方法是僅將類中的其他實體引用,而不通過通過外鍵放置關係來損害數據完整性。

  • 此外,某些數據+關係形成類似結構的圖形。持有直接實例引用也可能是一個問題。我不知道Hibernate如何在這種情況下工作。

+0

對不起,張貼這個答案,但評論限制你600字符。 會議會議=(會話)的EntityManager: – Chetan 2009-10-21 11:00:51

0

聽起來像你的用例不需要Hibernate,但其他的東西,因爲你基本上會在這裏「發明輪子」。您唯一的選擇是延遲加載B,以便當您調用A時,B和其對象圖被拉到僅當您明確呼叫getB()

1

我有同樣的問題,我希望能夠建立密鑰而不是使用所有這延遲加載的東西。我覺得冬眠到如此脆弱,錯誤和神祕的幽靈班到處都是。到目前爲止,這並不能簡化我的生活。試想一下:

模型(非常簡單):

Portfolio { 
... 
@OneToMany(cascade = {CascadeType.ALL}, fetch=FetchType.EAGER) 
@MapKey(name="symbol") 
public Map<String,Position> positions; 
} 
Position { 
    String symbol; int quantity; 
} 
Trade { 
    String symbol; int quantity; // price,etc 
... 
@ManyToOne() // looser coupling here. 
public Portfolio portfolio; 
} 

測試用例(注:全「enterTrade()」做的是堅持貿易在貿易表 在投資組合調整位置大小, '撤銷貿易()'只是恢復):

Trade trade1 = new Trade("GOOG", 25, portfolio); 
Trade trade2 = new Trade("GOOG", 50, portfolio); 
portfolio = portfolioDAO.enterTrade(trade1); 
portfolio = portfolioDAO.enterTrade(trade2); 

portfolio = portfolioSource.undoTrade(trade1, user); 
portfolio = portfolioSource.undoTrade(trade2, user); 
Assert.assertFalse(portfolio.getPositions().containsKey("GOOG"), 
     "after both trades net a position of zero"); 

這個測試應該正常嗎?錯誤!神祕地,投資組合中仍然有25個GOOG股。

的基本問題是trade2對象指向變得陳舊組合對象。最後的撤銷交易()操作使用仍然擁有75股GOOG的投資組合。請注意,Trade2永遠不會陳舊,因爲只有persist()已經被執行。但是當在Portfolio上執行update()時,會創建額外的副本,而不是更改原始對象(就像'persist()'所做的那樣)。我很難理解爲什麼這個設計不會被認爲是愚蠢和容易出錯的。這是一個簡單的例子。這不像我們正在談論的併發訪問問題或任何幻想。哦,當我嘗試刷新trade2時,得到LazyInitializationException,這完全是莫名其妙的。

所以,我的解決辦法是讓每一位需要刷新才能使用的密鑰是明確的:

Trade { 
    ... 
    @ManyToOne(targetEntity=Portofio.class) 
    @JoinColumn(referenceColumnName="id") 
    public Long portfolio_id; 
} 

或什麼的。儘管我在這裏表達了很多挫折,但我很樂意聽到如何解決這些問題的誠實解釋。謝謝。

+0

,我首先要到Hibernate的水平(我使用JPA)解決了我的核心問題。getDelegate(); session.update(p); //返回entityManager.merge(p); 原來,Hibernate API比實際發生的事情要優越和清晰。我想我可以完全轉向那個。 – Carlos 2009-10-26 21:55:14

1

好了,我知道這是一個古老的線程,但是這是相當普遍的,大多數人似乎冬眠沒有意識到,這是對我們這些無法保持會話整個要求開放問題。

做這樣的事情(使用註解,因爲這樣的例子是我很熟悉):


Class A 
{ 
private String id; 
private String name; 
private String type; 

@OneToOne(fetch=FetchType.LAZY) 
private B b; 
@Column(name="b_id", insertable=false, updatable=false) 
private String b_id; 
} 

這將導致不被默認爲獲取B,但即使經過B_ID將可會議關閉並通過類似推土機或吉利德的方式運行您的結果。 b_id的映射設置爲insertable = false和updatable = false,以便它是隻讀的,並且在寫回數據庫時將被忽略。要更新關聯,您必須設置實際的b字段。

相關問題