2016-03-30 17 views
10

短版的草率做法:最適合在JPA連接不同的實體類型

有各種表格/在我的域模型實體具有相同字段(UUID)。有一個表格,我需要將這些實體的行/實例鏈接到其他JPA管理的實體。換句話說,該鏈接表中字段的實例將不會被預先知道。我能想到的兩種方法是:

  • 使用一個抽象的實體和TABLE_PER_CLASS策略,或
  • 使用鏈接表的實例的@MappedSuperClass存儲類的名稱爲好,或者類似的東西,讓我定義了從右表獲取實際實例的邏輯。

兩者在複雜性和性能方面都有優點和缺點。你認爲哪一個最好,是否有第三種選擇,或者你過去是否嘗試過這樣的事情,並會提出建議/強烈警告?萬一

龍版您想了解更多的背景:

我有一個數據庫/對象模型,其中很多類型都有一個共同的領域:一個通用唯一標識符(UUID)。原因是這些類型的實例可能會發生變化。這些更改遵循命令模型,它們的數據可以被封裝並且自身持續存在。我們稱這種變化爲「突變」。必須能夠找出數據庫中對於任何給定實體存在哪些突變,反之亦然,存儲的突變在哪個實體上操作。

看看下面的實體的UUID作爲一種(非常簡化的)例子: mutable entities

要存儲「突變」,我們用一個表/實體,稱爲MutationHolder。要將突變連接到其目標實體,有一個MutationEntityLink。這個數據是不是直接在MutationHolder的唯一原因是因爲可以有直接或間接的聯繫,但在這裏,這並不重要,所以我離開了出來: mutation entities

問題歸結到我怎麼能建模entity字段MutationEntityLink。我可以想到兩種方法。

第一個是使用UUID字段對註釋類進行抽象@EntityCustomerContractAddress將擴展它。所以這是一個TABLE_PER_CLASS策略。我假設我可以將此作爲entity字段的類型,儘管我不確定。但是,我擔心這可能會導致嚴重的性能損失,因爲JPA需要查詢很多表以查找實際實例。

第二種方法是簡單地使用@MappedSuperClass並只存儲實體的UUID entity字段MutationEntityLink。爲了得到具有該UUID的實際實體,我必須以編程方式解決它。添加一個額外的列,其中包含實體的類名,或者其他可以讓我識別它或將其粘貼到JPQL查詢中的列。這需要更多的工作,但似乎更有效率。我不反對編寫一些實用工具類,或者根據需要做一些反射/自定義註釋工作。

我的問題是哪種方法最好?或者,你可能有更好的建議,或注意我錯過了一些東西;例如,可能有添加類型列的方法,即使使用TABLE_PER_CLASS繼承將JPA指向右表?也許你已經嘗試過這樣的事情,並想警告我會發生很多問題。

一些額外的信息:

  • 我們創建數據庫模式,所以我們可以添加任何我們想要的。
  • 單表繼承策略不是一個選項。表格必須保持不同。出於同樣的原因,加入繼承似乎也不適合。
  • JPA提供程序是Hibernate,使用不屬於JPA標準的東西不是問題。

回答

6

如果這些實體除了使用uuid之外沒有任何共同之處,我會使用第二種方法描述:使用MappedSuperclass。如果需要將公共超類作爲實體,將會阻止您使用不同的繼承策略,即使沒有實例存在,也需要該超級實體的表,並且從業務角度來看,這只是錯誤的。

鏈接本身可以用多種方式實現,例如,你可以爲每個實體映射MutationEntityLink以映射(例如CustomerMutationEntityLink等),或者像你描述的那樣做,即只存儲uuid以及一些鑑別器/類型信息並以編程方式解析(我們使用這種方法來處理類似的btw。 )。

+0

很高興聽到您實際使用該方法。這表明它是可行的。我認爲爲每個映射實體劃分MutationEntityLink會非常不方便,所以現在一種鑑別器列聽起來最好。 –

+0

@G_H是的,這是決定反對子類的原因。 – Thomas

+1

我喜歡@Thomas爲每個實體分派MutationEntityLink的想法。由於它是一個技術類,它提供了突變與實體之間的聯繫,所以我會選擇單表繼承。該表將具有其鑑別器列和每個實體的一個外鍵列。該表可能不是您的域模型最優雅的表示,但您可以從中獲得良好的性能。 –

2

在繼承關聯/方法/屬性時,您需要使用@MappedSuperclass,而當您有實體和子實體時,通常會使用TABLE_PER_CLASS。如果實體與模型中的基類有關聯,則使用TABLE_PER_CLASS,因爲基類的行爲類似於實體。否則,因爲基類將包括性能/特性,哪些是一般不相互關聯的這些實體的方法,使用@MappedSuperclass將是一個更好的主意

例1:您需要設置報警像一些不同的活動「吃藥」,「打電話給媽媽」,「去看醫生」等。報警信息的內容無關緊要,您需要提醒。因此,使用TABLE_PER_CLASS,因爲警報消息是基類,就像這裏的一個實體。

示例2:假設基類AbstractDomainObject使您可以爲每個沒有實體與基類關聯的對象創建登錄標識loginName,creation/modification date,您需要指定關聯之後清算,如「公司」,「大學」等。在這種情況下,使用@MappedSuperclass會更好。

+0

映射超類和表類繼承策略之間的區別已經很清楚了。我的情況所面臨的挑戰是,實際上有一個表需要引用抽象類實現的實體,但對於領域模型和性能而言'@ MappedSuperClass'比TABLE_PER_CLASS更有意義,所以要使用我想要的需要自己爲正確的實體類型創建查找邏輯。問題歸結爲這是否可行(托馬斯確認如此),以及是否存在現有解決方案/最佳實踐。 –