2011-08-25 121 views
2

我有以下情形:JPA /休眠,@OneToMany和約束(Oracle)的

@Entity 
class A { 

    @Id 
    @GeneratedValue 
    private long dbId; 

    @OneToMany (cascade = CascadeType.ALL) 
    @JoinColumn(name = "A_ID", referencedColumnName = "DBID") 
    Set<C> setOfCs; 

} 

@Entity 
class B { 

    @Id 
    @GeneratedValue 
    private long dbId; 

    @OneToMany (cascade = CascadeType.ALL) 
    @JoinColumn(name = "B_ID", referencedColumnName = "DBID") 
    Set<C> setOfCs; 

} 

@Entity 
class C { 

    @Id 
@GeneratedValue 
private long dbId; 

} 

表C與兩列A_ID和B_ID作爲外鍵分別A.DBID和B.DBID創建。這對我來說沒有什麼意義,因爲C中的每個元素都是從A或(xor)B鏈接的,但是不能同時連接(兩個關係都是一對多非多對多關係)。

是否有一種方法可以在A_ID和B_ID沒有外鍵約束的情況下擁有相同的表(這很好)?當我設置A-> C時,Oracle抱怨沒有設置C.B_ID。

感謝

利瑪竇

回答

1

你爲什麼不使用@JoinTable?它將刪除表C上的任何外鍵。

@OneToMany(cascade = CascadeType.ALL,fetch=FetchType.LAZY,orphanRemoval=true) 
@JoinTable(name = "A_B_TABLE", joinColumns = { @JoinColumn(name = "A_ID") },  inverseJoinColumns = { @JoinColumn(name = "DB_ID") }) 
public Set<C> getSetOfCs() { 
    return setOfCs; 
} 

順便說一句,不要註釋項目,而是在它的getter上做它。

+0

這樣做可以避免這個問題,但它會削弱參照完整性:如果A-C和B-C關係都用連接表處理,那麼就不可能確保存在某種關係。 –

+0

此外,你誤以爲getter訪問比field訪問更好;這主要是品味的問題,並且有[無論是哪種方式](http://blog.xebia.com/2009/06/jpa-implementation-patterns-field-access-vs-property-access/) - 我發現支持實地訪問的論據完全有說服力,正如它所發生的那樣。 –

+0

謝謝你解決我的問題。是的,它會在數據庫級別上失去一些完整性檢查,但這些檢查是(或者應該)由我們的應用程序確保的。如果擁有與原始示例中可空的外鍵相同的數據庫結構,那也不錯。由於在真正的應用程序中,我們與表格'C'有很多關係,所以我們將有許多額外的表格,但在第一次測試中似乎不是一個大問題。 – Matteo

0

我能想到的唯一方法就是通過一個通用的類強制兩個關係,C可以有一個外鍵。

最簡單的方法是引入一些X類,它們是A和B的超類,並且具有dbId和setOfC屬性。 C的表將會有一個列X_ID。

或者,使C抽象並引入子類Ca和Cb,使得A的實例始終引用Ca的實例,並將B的實例引用到Cb。 Ca和Cb中的每一個只需要一個外鍵。雖然這可能非常尷尬;這意味着你永遠不可能將C的實例從A轉移到B.

如果你不能引入任何基類,你可以將Wheeler's law和plaster應用於間接,結合上述兩種方法。創建一個抽象類X,並賦予其A和B的dbId和setOfC屬性; C然後與X有一個幻影ManyToOne關係,並且它有相應的外鍵。創建X,Xa和Xb的兩個具體子類,每個分別與A或B的實例具有OneToOne關係,A和B的實例具有指向另一個方向的相應OneToOne關係。

+0

是的,我也想過改變模型,但這(原因有幾個)只有我最後的選擇。 – Matteo