2012-02-25 110 views
3

我正在尋找建議或關於如何爲以下關係建模的備選方案。建模ORM中的繼承類型之間的關係

考慮:

enter image description here

並表示關係的應用:

enter image description here

督軍先生有很多選擇,但是如果資源消失,他的選擇級聯式刪除。現在槍支和子彈都是資源。槍支可以使用多種子彈,(FMJ,HP,P +,爆炸?)。子彈也可以用於各種槍支(AK,M60,M14)。因此,我還想確保如果Bullet不再可用,上述的槍支關係將不再存在,反之亦然。

希望我的幻想的榜樣可以獲得沃爾沃斯的清晰畫面。

資源是抽象的。雖然它們存在於數據存儲中用於約束目的,但我永遠不會實例化一個通用資源。而且我可以有更多的類型(手杖,直升機,狼人......),每個類型都有不同的屬性。它們存在於第一種情況中,以避免ChoicesEned的多態外鍵情況。

您會注意到資源類型2不包含Set<Type1>,而僅僅是對某些槍支的(Long)ResourceId的引用。 (子彈不能攜帶槍支,即使情況相反,並且爲了爭辯,是的,這些神奇的槍支可以射出許多類型的子彈)。

爲什麼我有ID的集合,而不是對象?那麼,如果我添加一種類型的項目符號,向關聯表添加Id引用似乎更有效,而不是檢索槍支並向其添加項目符號對象。這樣,當我檢索一個槍支對象時,我也不會檢索它可能使用的所有子彈。 (所有這些對象的內存開銷較小,而不僅僅是一堆Ids)。

那麼究竟是什麼問題?:

1)這似乎並不像一個常見的模式。有沒有更好的方法來建模?

2.)我是一個使用引用而不是對象的OOP異端嗎?我應該只使用對象嗎?

我的主要問題

3)如果1和2都沒有的情況下,我怎麼能在JDO模型呢?我已經做了幾天的試驗,而且我所面臨的問題是,JDO似乎無法識別長期套件之間的關係。我找到的每個示例都顯示了Composition對象的使用,而不是M-N屬性引用。如果我沒有指定另一個持久對象,那麼似乎有一些混淆。持久對象的屬性似乎不起作用。

UPDATE:

我今天從DataNucleus將論壇收到答覆,Here is the thread 的問題涉及到我上面的問題#2。我試圖節省一些內存開銷是我的困難之源。 我無法在元素類型不是其他元素類型的集合之間建立關係,而無需其他持久性類別。我需要重新設計一點。

SOLUTION:

見下

我的答案我感謝大家的投入。

+0

說資源只有一個共同的界面而沒有共同的存在是否準確?也就是說,永遠沒有理由將子彈和Perks列在一起。 – 2012-02-25 01:25:32

+0

@MarkRobinson - 我可能不會關注,但是Perks的列表實際上只能用於指導「訪問」。我不會同時需要Bullets和Perks,而是從Perks列表中選擇資源,然後再檢索這些資源以便一起使用。這是否解決你的問題? – Sp3igel 2012-02-25 01:52:55

+0

在這個設計中,我很難看到哪些資源帶到了桌子上。它在我看來像你需要一堆類型轉換來使用像這樣的資源。你能詳細解釋一下嗎?謝謝。 – 2012-02-25 08:45:54

回答

1

我不相信這個模型是un-achievable,所以我繼續試驗它。儘管不是由持久化類組成的集合,而是僅僅是這些持久化實例的ID,但最終的數據存儲模型無論如何都是相同的。

我想將關係每邊的多頭集合一起存儲在join table中。我也想確保這些多頭(代表該關係的遠端側的PK)將被配置爲複合PK,其中每一半都指向它所代表的表格。儘管看起來這是一個非常簡單的設置,但我仍然在重複JDO模式創建者在連接表中創建的第三列的問題。它不是將(長)ID與相關對象相匹配,而是將它們視爲「元素」並將它們傾倒到第三列中。這當然打破了主鍵,並導致在任何對象持久存在時拋出異常。

無文檔所提供的這種任何解決方案,所以我下面提供的:

  1. 我停止使用annotationsseperate ORM file並堅持只用package.jdo元數據文件。 (這可能不是必要的,但它是很好的做法(編輯的XMl與類),這讓事情變得更簡單。)

  2. 我給* 具體名稱的連接表列,以便他們不會自動生成其擁有。

  3. 我匹配關係兩邊的加入說明。這意味着指定表格和連接的列名稱。這不是在the docs建議,但這種方式的Id進入正確的列,無論他們來自哪個集合(之前沒有具體說明,他們顛倒了順序,並增加了更多的FK限制......爲什麼我不明白)。

所以.jdo元數據如下所示:

<class name="Firearm" table="APP_JDO_FIREARMS"> 
     <inheritance strategy="new-table"/> 
     <field name="name"/> 

     ... 
     <field name="bullets" mapped-by="firearms" table="APP_JDO_BULLET_FIREARM"> 
      <collection element-type="java.lang.Long"/> 
      <join> 
       <column name="FIREARM_ID"/> 
      </join> 
      <element> 
       <column name="BULLET_ID"/> 
      </element> 
     </field> 
    </class> 

    <class name="Bullet" table="APP_JDO_BULLETS"> 
     <inheritance strategy="new-table"/> 
     <field name="name"/> 

     ... 
     <field name="firearms" persistence-modifier="persistent" mapped-by="bullets" table="APP_JDO_BULLET_FIREARM"> 
      <collection element-type="java.lang.Long"/> 
      <join> 
       <column name="BULLET_ID"/> 
      </join> 
      <element> 
       <column name="FIREARM_ID"/> 
      </element> 
     </field> 
    </class> 

上述元數據是從正常的不同之處在於它指定在兩個兩端的聯接關係。通常你只需要在一邊指定它。在兩端做這件事情會更有力,並且不會讓JDO嘗試並找出要做的事情。

我已經確認,這種方式也正確設置了所有PK,FK約束。即使在刪除所有表並讓JDO重新創建它們之後,它也會根據需要執行它。

這對一些人來說可能是微不足道的,但是這花了我很多時間去解決。希望將來可以挽救別人頭痛的問題。

1

我不知道JDO,因此我將從JPA的角度以一般方式回答您的問題。

當涉及到使用ORM映射繼承時,您需要問自己以下問題。

1)您是否在尋找多態查詢支持。即,是否要爲資源類型的對象執行查詢並取回類型爲Bullets和Fire武器的對象列表。

如果您不需要多態查詢,您將希望使用@MappedSuperclass,這意味着您的基類包含用於映射由子類繼承的元數據的註釋,但基類本身沒有標識,因此不可查詢,但可以查詢子類。

如果您確實需要多態查詢,那麼您可以有三種可能的表結構來映射繼承,這些表結構在JPA中稱爲策略。每個具體類

  1. 與鑑別列每班
  2. 一個表繼承層次結構(你有你的問題)

每個這三個繼承映射策略單桌在他們投入數據庫的努力方面有其優點和缺點。例如帶有鑑別器列的單個表會導致一個有很多列的稀疏表,但是多態查詢不需要連接。

許多JPA書籍都很好地解釋了這三種方法之間的權衡,重要的是要確保您知道這些權衡是什麼,以便您可以爲您的應用選擇最佳方法。

http://www.apress.com/9781430219569對映射繼承的問題進行了體面的討論。

+0

嗨阿姆斯 - JDO其實有幾乎相同的策略,所以你的想法是非常適用的。我爲這個問題增加了一些額外的信息。 – Sp3igel 2012-02-25 19:45:26