JPA - отношение один к одному с общим первичным ключом между несколькими таблицами - PullRequest
0 голосов
/ 05 октября 2011

Рассмотрим приведенный ниже пример:

У меня есть 3 стола: фрукты, апельсин и яблоко

id генерируется в таблице фруктов и является первичным ключом здесь

id также является первичным ключом для Orange и Apple (общий первичный ключ)

Так, например, если id во фруктах равен 1, 2, 3, 4, 5 - тогда сценарий может быть 1, 2 - оранжевым, 3, 4 - яблочным, а 5 - оранжевым.

Таким образом, таблица Orange будет иметь идентификатор 1,2,5, а таблица Apple будет иметь идентификатор 3, 4

=================================== 
 Fruit
===================================
 id     |   shape
===================================
  1     |   round
  2     |   round
  3     |   oblong
  4     |   oblong
  5     |   round
===================================


===================================
 Orange
===================================
 id     |   color    | taste
===================================
  1     |   orange   |  sour
  2     |   orange   |  sour
  5     |   orange   |  sour
===================================


===================================
 Apple
===================================
 id     |   density    | weight
===================================
  1     |   hard       |  200
  2     |   hard       |  220
  5     |   hard       |  230
===================================

Проблема: как создать классы сущностей, захватывающие отношения, связанные только с аннотациями JPA (я не хочу использовать аннотацию сгенерированного значения hibernate).

Если такая аннотация возможна для чистого JPA, то, пожалуйста, направьте меня к ней.

Nik

Ответы [ 2 ]

2 голосов
/ 31 июля 2012

Ваш случай выглядит как пример шаблона проектирования, известного как «Специализация обобщения» или Gen-Spec для краткости.Вопрос о том, как смоделировать gen-spec с использованием таблиц базы данных, постоянно возникает в SO.

Если бы вы моделировали gen-spec в OOPL, таком как Java, вы бы использовали средство наследования подклассов, чтобы позаботитьсяиз деталей для вас.Вы просто определили бы класс, который позаботится об обобщенных объектах, а затем определите коллекцию подклассов, по одному для каждого типа специализированного объекта.Каждый подкласс расширил бы обобщенный класс.Это легко и просто.

К сожалению, реляционная модель данных не имеет встроенного наследования подклассов, и, насколько мне известно, системы баз данных SQL не предоставляют никаких таких возможностей.Но тебе не повезло.Вы можете спроектировать свои таблицы для моделирования gen-spec таким образом, чтобы это соответствовало структуре классов ООП.Затем вам нужно организовать собственный механизм наследования при добавлении новых элементов в обобщенный класс.Подробности приведены ниже.

Структура класса довольно проста: одна таблица для класса gen и одна таблица для каждого подкласса spec.Вот хорошая иллюстрация с сайта Мартина Фаулера. Наследование таблицы классов .Обратите внимание, что на этой диаграмме Cricketer является одновременно подклассом и суперклассом.Вы должны выбрать, какие атрибуты идут в какие таблицы.На диаграмме показан один примерный атрибут в каждой таблице.

Сложность в том, как определить первичные ключи для этих таблиц.Таблица классов gen получает первичный ключ обычным способом (если только эта таблица не является специализацией еще одного обобщения, такого как крикетисты).Большинство дизайнеров дают первичному ключу стандартное имя, например, «Id».Они используют функцию автонумерации для заполнения поля Id.Таблицы классов спецификации получают первичный ключ, который может называться «Id», но функция автонумерации не используется.Вместо этого первичный ключ каждой таблицы подклассов ограничен ссылкой на первичный ключ обобщенной таблицы.Это делает каждый из специализированных первичных ключей как внешним ключом, так и первичным ключом.Обратите внимание, что в случае игроков в крикет поле Id будет ссылаться на поле Id в проигрывателе, а поле Id в Боулерах будет ссылаться на поле Id в игроке в крикет.

Теперь, когда вы добавляете новые элементы, вы должны поддерживать ссылочную целостность, вот как.
Сначала вы вставляете новую строку в таблицу gen, предоставляя данные для всех ее атрибутов, кроме первичного ключа.,Механизм автонумерации генерирует уникальный первичный ключ.Затем вы вставляете новую строку в соответствующую таблицу спецификаций, включая данные для всех ее атрибутов, включая первичный ключ.Используемый вами первичный ключ - это копия только что созданного первичного ключа.Такое распространение первичного ключа можно назвать «наследованием бедняков».

Теперь, когда вам нужны все обобщенные данные вместе со всеми специализированными данными только из одного подкласса, все, что вам нужно сделать, это объединить две таблицыпо общим ключам.Все данные, которые не относятся к рассматриваемому подклассу, будут исключены из объединения.Это гладко, легко и быстро.

Дизайн таблиц SQL, которые реализуют шаблон gen-spec, может быть немного сложным.Учебники по дизайну баз данных часто затмевают эту тему.Но на практике это происходит снова и снова.

Если вы будете искать в Интернете «обобщение специализации реляционное моделирование», вы найдете несколько полезных статей, которые научат вас, как это сделать.Вам также будет несколько раз указано, что эта тема поднималась раньше на этом форуме.

В статьях обычно показывается, как выw разработать единую таблицу для сбора всех обобщенных данных и одну специализированную таблицу для каждого подкласса, которая будет содержать все данные, относящиеся к этому подклассу.Интересная часть включает в себя первичный ключ для таблиц подклассов.Вы не будете использовать функцию автонумерации СУБД для заполнения первичного ключа подкласса.Вместо этого вы запрограммируете приложение на распространение значения первичного ключа, полученного для обобщенной таблицы, в соответствующую таблицу подклассов.

Это создает двустороннюю связь между обобщенными данными и специализированными данными.Простое представление для каждого специализированного подкласса будет собирать обобщенные и специализированные данные вместе.Это легко, когда вы освоите его, и он работает довольно хорошо.

0 голосов
/ 05 октября 2011

Для проверки путем принудительного сопоставления двух полей Java (идентификатора и ассоциации) в одном столбце.

Например,

class Orange {

   @Id
   @Column(name="id")
   long id;


   @OneToOne
   @JoinColumn(name="id")
   Fruit fruit;

   public Orange(Fruit fruit) {
      this.fruit = fruit;
      this.id = fruit.id;
   }

   protected Orange() { } // default constructor required by JPA
}

Но я не знаю, как поведет себя провайдер JPA.

...