2012-02-25 113 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