2013-06-07 8 views
4

У меня есть следующие JPA 2.0 EntitiesВ иерархии сущностей JPA с помощью InheritanceType.JOINED, все отношения с подклассов приводит ограничений внешнего ключа на таблицу суперкласса

@Entity 
@Inheritance(strategy= InheritanceType.JOINED) 
public abstract class BookKeepingParent implements Serializable { 
    @Id 
    protected Long Id; 
    ... 
} 

@Entity 
public class Employee extends BookKeepingParent { 
    private String name; 

    @ManyToOne 
    private Role role; 
    ... 
} 

@Entity 
public class Role extends BookKeepingParent { 
    private String name; 
    ... 
} 

Я хочу, чтобы JPA генерировать таблицы для меня, поскольку он упрощает установку в нескольких местах. Я обычно ожидал, что для создания этого:

CREATE TABLE bookkeepingparent (
    id bigint NOT NULL, 
    dtype character varying(31), 
    CONSTRAINT bookkeepingparent_pkey PRIMARY KEY (id) 
) 

CREATE TABLE role (
    id bigint NOT NULL, 
    name character varying(255), 
    CONSTRAINT role_pkey PRIMARY KEY (id), 
    CONSTRAINT fk_role_id FOREIGN KEY (id) REFERENCES bookkeepingparent (id) 
) 

CREATE TABLE employee (
    id bigint NOT NULL, 
    name character varying(255), 
    role_id bigint, 
    CONSTRAINT employee_pkey PRIMARY KEY (id), 
    CONSTRAINT fk_employee_id FOREIGN KEY (id) REFERENCES bookkeepingparent (id), 
    CONSTRAINT fk_employee_role_id FOREIGN KEY (role_id) REFERENCES role (id) 
) 

Первые две таблицы, где же, но она породила employee стол таким образом:

CREATE TABLE employee (
    id bigint NOT NULL, 
    name character varying(255), 
    role_id bigint, 
    CONSTRAINT employee_pkey PRIMARY KEY (id), 
    CONSTRAINT fk_employee_id FOREIGN KEY (id) REFERENCES bookkeepingparent (id), 
    CONSTRAINT fk_employee_role_id FOREIGN KEY (role_id) REFERENCES bookkeepingparent (id) 
) 

Вы можете заметить, что fk_employee_role_id ссылается на bookkeepingparent стол, вместо таблицы role. У меня есть большая иерархия сущностей JPA, и я хочу, чтобы бухгалтерский учет был суперклассом большинства из них. Это в первую очередь из-за некоторых очень специфических стратегий генерации идентификаторов и других видов ведения бухгалтерского учета. Этот дизайн помогает сохранить весь этот код хранения книг отдельно от функционального кода и позволить программистам, работающим над функциональным кодом, не беспокоиться об этом.

Все это работало нормально, пока не выросло количество столов. Теперь мы видим, что для всех отношений ManyToOne и OneToOne JPA генерирует внешние ключи, относящиеся к родительской таблице. С 200 нечетными таблицами вставки уже медленны, потому что все ограничения внешнего ключа относятся к элементу bookekeepingparent, и каждый объект, когда он сохраняется в первый раз, вставляется в родительскую таблицу бухгалтерии. Кажется, я проверяю около 150 нечетных ограничений.

Итак, следующие вопросы: почему JPA это делает? Является ли это стандартным поведением JPA? (Я использую EclipseLink). Если я вручную изменю схему БД, их любые подводные камни ожидать?

Это мой первый вопрос о StackOverflow, я старался изо всех сил искать любые существующие ответы. Извиняюсь, если я пропустил. Благодарю.

+0

Я согласен с вами в том, что FK должен ссылаться на подклассы. Это похоже на ошибку в EclipseLink, поскольку такое отображение, по-видимому, неверно и не отражает отношения правильно. –

ответ

1

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

Ограничения базы данных не связаны с JPA, поэтому вы можете изменять их по мере необходимости и не влиять на приложение, если обновления и удаления вложений по-прежнему будут соответствовать.

+0

Предположим, JPA нужны кэши для операций типа EntityManager.find(). Поскольку идентификаторы суперкласса и подкласса одинаковы, не имеет значения, какой из них вы используете в качестве «ключа» кеша. Кроме того, о ограничениях БД - те, которые создает EclipseLink, являются своего рода «неточными» - наличие внешнего ключа, относящегося к суперклассу, позволяет добавлять в таблицу столбцов Employee идентификаторы таблиц, отличных от роли. Таким образом, мои вставки и обновления, несомненно, будут соответствовать ограничению, потому что мои уже, чем те, которые EclipseLink ставит. Поэтому я до сих пор не понимаю, почему они это делают. В любом случае спасибо. – Nikhilesh

+0

Как уже упоминалось, основная таблица - это учетная запись, поэтому значения по умолчанию всегда будут указывать на эту таблицу в EclipseLink. Вы можете изменить его, указав joincolumn на сопоставлении, чтобы перейти во вторичную таблицу, которая изменит ограничение, созданное для DDL, но, скорее всего, у него не будет возврата к кешу.Поэтому, вероятно, лучше изменить ваши сценарии DDL, чем сопоставления – Chris

+0

Если я изменю DDL-скрипты, чтобы FK ссылалась на таблицу подкласса, я получаю ошибку нарушения ограничений. Так что это не решение. Для меня это похоже на ошибку в EclipseLink, поскольку она не представляет объектных отношений. –