Java ORM:多(接口)继承

7
我希望使用Java的ORM框架将领域模型映射到关系数据库。不幸的是,这些框架似乎都没有为实现多个接口的类提供足够的支持。例如,我想要映射以下类型:
public interface Quotable {
}

public interface Tradable {
}

// StockIndex only implements Quotable as it cannot be trade directly
public class StockIndex implements Quotable {
}

// Stock implements both interfaces as there are market quotes and can be traded
public class Stock implements Quotable, Tradable {
}

public class Quote {
    private Quotable quotable;
}

public class Trade {
    private Tradable tradable;
}

所以我想实现的是,报价可以引用任何可引用物(股票、股票指数和其他),而交易只能引用可交易实体。我已经尝试使用OpenJPA和(纯)Hibernate,但都没有成功,尽管后者对接口的支持看起来很有前途。
有没有框架可以处理我的情况?或者有没有很好的理由不将其映射到数据库中?如果有,应该如何修改我的模型?
我的初始Hibernate映射大致如下(我没有显示任何OpenJPA的内容,因为它不支持接口继承,或者至少我无法弄清楚):
<hibernate-mapping package="com.foo">
    <class name="Quotable" table="quotable" >
        <id type="java.lang.Long" column="id">
            <generator class="sequence" />
        </id>

        <discriminator column="type" type="string" />

        <subclass name="StockIndex">
            <join table="stock_index" >
                <key column="id"/>
                <property name="name" column="name" access="field" />
            </join>
        </subclass>

        <subclass name="Stock">
            <join table="stock" >
                <key column="id"/>
                <property name="name" column="name" access="field" />
            </join>
        </subclass>
    </class>
</hibernate-mapping>

这与Hibernate文档中的示例几乎完全相同,将产生一个带有id和字符串判别器列的表quotable、一个带有id和指数名称的表stock_index以及一个带有id和股票名称的表stock。到目前为止还不错...但是,我该怎么处理Tradeable接口?我必须设置一个单独的层次结构,并在两个层次结构中映射Stock。我确实尝试过这样做,但必须为Stock定义不同的实体名称(并需要包含此修补程序),但由于外键冲突,这也行不通。我尝试了一些其他不起眼的事情,但也没有成功。总之,两次映射股票不是一个好的解决方案,因为应用程序必须记住为每个接口添加两次股票实例。我宁愿让框架自动处理这个问题。

理想情况下,Hibernate会允许扩展多个接口,例如:(请注意“subclass”元素上的“extends”属性):

<subclass name="Stock" extends="Quotable, Tradable" >
    <join table="stock" >
        <key column="id"/>
        <property name="name" column="name" access="field" />
    </join>
</subclass>

是否还有其他映射示例的想法?我现在了解到了<any>元素,它看起来可能适合我,但我仍需理解其所有含义。

其他框架呢?我听说EclipseLink也支持接口,但文档不够完善。


5
你并没有真正解释什么出了问题,或者你是如何进行映射的。 - Dave Newton
我现在已经包含了更详细的Hibernate映射,说明了我尝试过的一些内容。希望现在变得更加清晰明了。 - kaiboy
1个回答

3
我认为你不会找到任何ORM能够很好地处理接口层次结构。因此,我在这里不会谈论ORM,但我将向您展示如何使用Qi4j实现您的示例。
Qi4j是一个基于组合导向编程的实现,使用标准Java平台和领域中心应用程序开发框架,包括来自AOP、DI和DDD的进化概念。请参见http://qi4j.org 在Qi4j中,领域状态使用实体和值进行建模。在下面的代码示例中,我假设所有内容都是实体,但您的情况可能有所不同。
由于实体仅使用接口声明,因此您的用例应该能够很好地适配。
interface Quotable { ... }
interface Tradable { ... }
interface StockIndex extends Quotable { ... }
interface Stock extends Quotable, Tradable { ... }
interface Quote {
    Association<Quotable> quotable();
}
interface Trade {
    Association<Tradable> tradable();
}

你可以将它们存储在EntityStore中,并使用Query API轻松检索它们(并以完全多态的方式)。
请注意,Qi4j EntityStores不仅基于SQL,还支持NoSQL数据库。请查看此处提供的可用扩展:http://qi4j.org/latest/extensions.html 如果您有更多问题,请参阅Qi4j文档。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接