将继承类型之间的关系建模为ORM

时间:2012-02-25 00:37:45

标签: java jpa orm jdo data-modeling

我正在寻找有关如何建模以下关系的建议或替代方案。

考虑:

enter image description here

和所述关系的应用:

enter image description here

先生。督军有很多选择,但如果资源消失,他的选择会逐步消除。现在火器和子弹都是资源。枪支可以使用多种子弹,(FMJ,HP,P +,Explosive?..)。子弹也可用于各种枪支(AK,M60,M14)。因此,我还想确保如果Bullet不再可用,上述Firearm关系将不再存在,反之亦然。

希望我的收获军阀的典型例子描绘了一幅清晰的画面。

资源是抽象的。虽然它们存在于数据存储区中以用于约束目的,但我永远不会实例化通用资源。我可以有更多类型(心腹,直升机,狼人......),每个类型都有不同的属性。它们存在于第一种情况下,以避免ChoicesEarned出现多态外键情况。

您会注意到资源类型2不包含Set<Type1>,而只包含对某些Firearm的(Long)ResourceId的引用。 (子弹不能拿枪支,即使反过来也是如此,为了争论,是的,这些神奇的枪可以射击多种类型的子弹)。

为什么我有ID的集合,而不是对象?好吧如果我添加一种子弹,向关联表添加Id引用似乎比检索枪支并向其添加子弹对象更有效。这样,当我检索枪支对象时,我也不会检索它可能使用的所有子弹。 (所有这些对象的内存开销减少,而只是一堆ID)。

那么问题是什么?:

1。)这似乎不是一种罕见的模式。有没有更好的方法对其进行建模?

2。)我是OOP异教徒使用引用代替对象吗?我应该只使用对象吗?

我的主要问题

3。)如果不是1和2,我如何在JDO中对此进行建模?我已经进行了几天的实验,我一直遇到的问题是JDO似乎无法识别Longs集之间的关系。我找到的每个例子都显示了Composition对象的使用,而不是M-N属性引用。如果我没有指定另一个持久化对象,那么似乎有些混乱。持久化对象的属性似乎不起作用。

更新

我今天收到了DataNucleus论坛的回复,Here is the thread 问题与我上面的问题#2有关。我节省一些内存开销的尝试是我困难的根源。 我无法在没有陪审团操纵的元素类型不是其他持久类的集合之间建立关系。我需要重新设计一下。

SOLUTION:

请参阅下面的答案

我感谢大家的意见。

2 个答案:

答案 0 :(得分:1)

我不知道JDO所以我将从JPA的角度以及一般方式回答你的问题。

在使用ORM映射继承时,您需要问自己以下问题。

1)您是否在寻找ploymorphic查询支持。即,您是否要查询资源类型的对象,并获取Bullets和Fire arms类型的对象列表。

如果您不需要多态查询,则需要使用@MappedSuperclass,这意味着您的基类包含用于映射子类继承的元数据的注释,但基类本身没有标识,因此不可查询但您可以查询子类。

如果确实需要多态查询,那么可以有三种可能的表结构用于映射继承,这些在JPA中称为策略。

  1. 每个具体类的表
  2. 带有鉴别列的单表
  3. 继承层次结构中每个类一个表(在您的问题中有什么)
  4. 这三种继承映射策略中的每一种在它们放在数据库上的努力方面都有它们的优缺点。例如,带有discriminator列的单个表将导致具有大量列的稀疏表,但多态查询不需要连接。

    许多JPA书籍都很好地解释了这三种方法之间的权衡,重要的是要确保你知道这些权衡是什么,这样你就可以为你的应用选择最好的方法。

    http://www.apress.com/9781430219569对映射继承的问题进行了很好的讨论。

答案 1 :(得分:1)

我不相信这个模型是un-achievable,所以我继续尝试它。尽管这些集合不是由持久化类组成的,而是仅仅是那些持久化实例的ID,但最终的数据存储模型将是相同的。

我希望将关系两侧的长片集合存储在join table中。我还想确保将这些long(代表关系的侧的PK)配置为复合PK,每一半都指向它所代表的表。尽管看起来这是一个非常简单的设置,但我在JDO模式创建者的连接表中创建了第三列的重复问题。它不是将(Long)Id与相关对象匹配,而是将它们视为“元素”并将它们转储到第三列。这当然打破了主键,并导致在任何对象被持久化时抛出异常。

没有任何文件提供任何解决方案,所以我在下面提供:

  1. 我停止使用annotationsseperate ORM file并且只使用了package.jdo元数据文件。 (这可能没有必要,但这是一个很好的做法(编辑XMl与班级)并使事情变得更简单。)

  2. 我将* 特定名称添加到连接表列,以便它们不会自动生成自己的名称。

  3. 我在关系的两边都匹配了连接说明。这意味着指定表,连接列名称。在the docs中没有提出这一点,但是这样,Id会进入正确的列,无论它们来自哪个集合(之前没有具体说明,它们会颠倒顺序并添加更多FK约束...为什么我不明白)。
  4. 因此.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重新创建它们之后,它也可以根据需要进行。

    这对某些人来说可能是微不足道的,但这花了我很多时间来解决问题。希望它能在未来挽救别人的头痛。