Java ORM: множественное (интерфейсное) наследование - PullRequest
6 голосов
/ 02 апреля 2012

Я бы хотел отобразить модель предметной области в реляционную базу данных, используя одну из сред ORM для Java. К сожалению, ни один из них не имеет адекватной поддержки классов, реализующих несколько интерфейсов. Скажем, я хочу отобразить что-то вроде:

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;
}

Итак, я пытаюсь добиться того, чтобы Цитата могла ссылаться на любой Котировочный материал (Stock, StockIndex и другие), тогда как Сделка может ссылаться только на Торгуемые сущности. Я попробовал 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 и приводит к таблице quotable с идентификатором и столбцу распознавателя строк, таблице stock_index с идентификатором и индексом 'имя и таблица акция с идентификатором и названием акции. Пока все хорошо ...

Но что мне делать с интерфейсом Tradeable? Я должен был бы установить отдельную иерархию и отобразить запас в обеих иерархиях. Я попробовал это, но мне пришлось определить разные имена сущностей для Stock (и мне нужно было включить этот патч ), но это также не сработало из-за нарушений внешнего ключа. Я попробовал несколько других непонятных вещей, которые тоже не работали.

В любом случае, отображение Stock дважды не будет хорошим решением, так как приложению придется помнить о добавлении экземпляров Stock дважды - по одному разу для каждого интерфейса. Я бы предпочел, чтобы рамки обрабатывали это автоматически.

В идеале Hibernate допускает расширение нескольких интерфейсов, то есть что-то вроде (обратите внимание, атрибут extends в элементе подкласса ):

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

Любые другие идеи, как мой пример может быть отображен? Теперь я узнал об элементе <any>, который выглядит так, как будто он может работать на меня, но я еще не понял всех его последствий.

Как насчет других фреймворков? Я слышал, что EclipseLink также имеет некоторую поддержку интерфейсов, но она недостаточно хорошо документирована.

1 Ответ

3 голосов
/ 01 ноября 2012

Я не думаю, что вы найдете какой-либо ORM, способный хорошо обрабатывать иерархию интерфейсов. Поэтому я не буду говорить об ORM здесь, но я покажу вам, как реализовать ваш пример с использованием Qi4j.

Qi4j - это реализация Composite Oriented Programming, использующая стандартную платформу 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 и использовать API запросов для их простого (и полностью полиморфного) извлечения.

Обратите внимание, что Qi4j EntityStores не только основаны на SQL, но также поддерживают базы данных NoSQL. Смотрите доступные расширения здесь: http://qi4j.org/latest/extensions.html

Если у вас есть вопросы, обратитесь к документации по Qi4j.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...