2009-06-26 31 views
4

A polymorphic association類似於外鍵或多對一關係,區別在於目標可能是多種類型之一(語言中的類,db中的表)。如何在JPA中表示多態關聯?

我正在移植一個數據庫設計,我從PHP到Java已經使用了好幾年了。在舊代碼中,我推出了自己的ORM,由於多種原因,這並不是最優的。雖然我可能會稍後開始調整,也許最終會再次自己實現,因爲現在我想在實體類中使用現成的ORM和JPA。

現在,有一件事是關於數據庫的佈局,我不知道如何在JPA表示:

我有一個NodeEdge表中存儲一個圖(DAG後,如果它事項)。每個節點可以選擇引用數據庫中的另一個實體。這些實體可能在整個圖表中被多次引用,並且也可能存在「孤兒」實體,這對用戶來說是不可訪問的,但是可能有意義的是保持至少一段時間。

這些對象在繼承等方面並不完全相關,但具有自然層次結構,類似於Customer-> Site-> Floor-> Room。事實上,多年前,我剛開始時只使用了指向「父」對象的外鍵字段。但是,這種層次結構不夠靈活,並開始分崩離析。

例如,我想允許用戶對文件夾中的對象進行分組,一些對象可以有多個「父母」,並且關係隨時間而改變。我需要跟蹤關係是如何的,因此圖的edegs有一個與它們相關的時間跨度,從何時到何時該邊是有效的。

從節點到對象的鏈接存儲在節點表的兩列中,一個攜帶外部表中的id,一個攜帶它的名稱。例如(某些列省略):

table Node: 
+--------+-------+----------+ 
| ixNode | ixRef | sRefType | 
+--------+-------+----------+ 
| 1 | NULL | NULL | <-- this is what a "folder" would look like 
| 2 | 17 | Source | 
| 3 | 58 | Series | <-- there's seven types of related objects so far 
+--------+-------+----------+ 

table Source (excerpt): 
+----------+--------------------+ 
| ixSource |  sName  | 
+----------+--------------------+ 
| 16 | 4th floor breaker | 
| 17 | 5th floor breaker | 
| 18 | 6th floor breaker | 
+----------+--------------------+ 

可能有與使用JPA不同的解決方案。我可以改變一些關於表格佈局或者引入一個新表格等等。然而,我已經想到了很多,表格結構對我來說似乎還可以。也許還有第三種方式,我沒有想到。

回答

0

Source和Series表中存儲了多少信息?這只是一個名字嗎?如果是這樣,你可以將它們組合成一個表格,並添加一個「類型」列。您的節點表將失去其sRefType,你將有一個新的表看起來像這樣:

ixSource  sName     sType 
    16   4th floor breaker  SOURCE 
    17   5th floor breaker  SOURCE 
    18   6th floor breaker  SOURCE 
    19   1st floor widget  SERIES 
    20   2nd floor widget  SERIES 

此表將取代來源和系列表。 Source和Series都屬於超類嗎?這將是這張桌子的自然名稱。

+0

對不起,但那對我不起作用。表格中有更多的信息,還有更多的表格,這些例子被簡化了。有很多種類型的對象,我需要一個圖表來更靈活地表達它們之間的關係。 – 2009-06-29 07:43:36

+0

也許,我可以想象某種抽象的RelatedEntity和一個存儲鍵值對的泛型屬性表,但這似乎有點過分了。我幾乎沒有db中的結構化信息了。 – 2009-06-29 08:23:21

5

我想你已經找到了答案。創建一個抽象類(@Entity或@MappedSuperclass),並用不同的類型擴展它。

像這樣的東西可能會奏效

@MappedSuperclass 
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) 
public abstract class Edge { 
    // . . . 
    @OneToMany 
    Collection<Node> nodes; 
} 

@Entity 
public class Source extends Edge { 
} 

@Entity public class Series extends Edge { 
} 

@Entity 
public class Node { 
    // . . . 
    @ManyToOne 
    Edge edge; 
} 

我知道你可能不希望暗示源和系列之間的關係,但延伸的公共抽象(表少)班是我能想到的唯一辦法做你想做的事。

InheritanceType。TABLE_PER_CLASS會將Source和Series保留在單獨的表中(您可以使用SINGLE_TABLE執行類似上一個回答的操作)。

如果這不是您正在尋找的內容,許多JPA提供程序提供了一種基於現有表創建映射的工具。在OpenJPA中,它被稱爲ReverseMappingTool [1]。該工具將生成可用作映射起點的Java源文件。我懷疑Hibernate或者EclipseLink有類似的東西,但是你可以使用OpenJPA,並且使用不同提供者的實體定義(據我所知,該工具不生成任何OpenJPA特定的代碼)。

[1] http://openjpa.apache.org/builds/latest/docs/manual/manual.html#ref_guide_pc_reverse

+0

這將非常容易實現,但我沒有得到的是:持久性提供程序如何知道將哪個類實例化爲Node中特定行的引用對象? – 2009-06-30 11:59:46

2

有你看了@Any註釋?它不是JPA的一部分,但是它是一個Hibernate Annotation擴展。

5

答案是:

  • 繼承(由Mike已經建議)
  • @DiscriminatorColumn提供的列存儲有關應該使用哪個子類中的信息:sxRef。我看到的唯一疑問是「sxRef」是可以爲空的列。我想這是被禁止的。