Как сделать связь manytomany в hibernate

Добавил пользователь Евгений Кузнецов
Обновлено: 10.09.2024

Hibernate — библиотека для языка программирования Java, предназначенная для решения задач объектно-реляционного проецирования (object-relational mapping — ORM). Она представляет собой свободное программное обеспечение с открытым исходным кодом (open source), распространяемое на условиях GNU Lesser General Public License. Данная библиотека предоставляет лёгкий в использовании каркас (фреймворк) для отображения объектно-ориентированной модели данных в традиционные реляционные базы данных.

В этой статье будут раскрыты основы использования Java ORM-библиотеки Hibernate 3-й версии на небольшом примере.

В качестве среды разработки использовался NetBeans версии 7.1. Для начала создайте Maven-проект в NetBeans:

Добавим зависимости в проект. Полный файл pom.xml показан ниже:

Также нам понадобится конфигурационный файл hibernate:

В данном примере для доступа к базе данных hibernate_basics используется пользователь hb_user с паролем hb_password. Измените эти параметры на используемые Вами.

Дамп используемой базы представлен ниже:

Структура проекта, в том числе, где располагается конфигурационный файл hibernate.cfg.xml показана на Рис.1.

Рис 1. Структура проекта


Рис 1. Структура проекта

Приступим к реализации взаимодействия с базой. Начнем с создания базового класса для работы с Hibernate и, соответственно, с базой данных. Создадим в пакете com.seostella.hibernate.basics.dao класс DAO:

Этот класс содержит базовые методы для работы с Hibernate: getSession() - получение сессии, begin(), commit(), rollback() - начало, комит и откат транзакции соответственно, close() - закрытие сессии.

Внимание! Объект SessionFactory является "тяжеловесным" - на его создание уходит много времени. Поэтому старайтесь этот объект инициализировать только раз, либо как можно реже.

Приступим к созданию объектов. Начнем с класса для работы с объектом User:

Аннотация @Entity используется для того, чтобы сообщить Hibernate, что класс взаимодействует с Hibernate. Также необходимо сообщить о том, что добавился маппинг-файл, добавив в конфигурационный файл hibernate.cfg.xml строку "mapping Пример:

Если у Вас есть jar-файл, состоящих из классов, помеченных как @Entity, Вы можете добавить его одной строкой:

Рассмотрим остальные аннотации, которые использовались в этом классе, а именно: @Table, @Column, @Id, @GeneratedValue.

@Table - аннотация, используемая для явного указания названия таблицы. Так как база данных содержит таблицу "hb_user", а не просто "user", была использована аннотация @Table(name="hb_user") чтобы явно указать название таблицы.

@Column - использовалась в примере для указания уникальности имени пользователя следующим образом:

@Id - аннотация используется для указания Primary-ключа;

@GeneratedValue - сообщает Hibernate, что значение должно генерироваться автоматически при добавлении нового объекта в базу.

Последние две аннотации используются в примере вместе с полем id:

Теперь создаем DAO-класс для работы с объектами User:

Как видно из примера, всё достаточно просто: для сохранения, поиска и удаления пользователя используются следующие соответствующие строки кода:

Для обеспечения целостности базы и для защиты от ошибок код обрамляется следующим образом:

Создадим главный класс UserApp для демонстрации выше приведенного кода:

Вы можете запустить этот класс на выполнение и, используя клавиши "1", "2" и "3", добавить, найти и удалить пользователя соответственно. Пример работы программы:

Аналогичным способом (по отношению к классу User) создаем классы Article и Category:

Рассмотрим новые аннотации @ManyToOne, @JoinColumn, @ManyToMany и @JoinTable:

@ManyToOne - аннотация применяется к полю если таблица связана с другой таблицей типом один-ко-многим;

@JoinColumn - с помощью этой аннотации указывается название поля таблицы, по которому происходит связь один-ко-многим с другой таблицей;

В нашем случае таблицы user и article связаны между собой связью один-ко-многим по полю user_id таблицы article. Поэтому в классе Article поле user_id описано следующим способом:

Как видим, Hibernate упрощает жизнь, сразу же возвращая объект User, вместо лишь одного идентификатора пользователя.

В нашем примере также есть связь многие-ко-многим между таблицами article и category через промежуточную таблицу category_article. Чтобы указать эту связь в Hibernate необходимо воспользоваться аннотациями @ManyToMany и @JoinTable. В одном из классов Article или Category необходимо прописать инструкцию вида @ManyToMany(mappedBy = ". "), а в другом:

В примере использовались следующие методы для этой связи. Класс Article, метод getCategories():

И соответствующий код в классе Category:

Грубо говоря, в одном из классов должна быть привязка к промежуточной таблице category_article, а во втором - привязка к первому классу с помощью выражения mappedBy.

Обратите внимание, что названия методов getArticles() и getCateories() соответствуют названиям полей articles_id и categories_id в таблице category_article. То есть, название поля = название метода без стартового get.

Добавляем эти классы в конфигурационный файл hibernate.cfg.xml:

Рассмотрим DAO-классы: ArticleDAO и CategoryDAO. Начнем с CategoryDAO:

Как видим, класс CategoryDAO существенно отличается от UserDAO лишь одним методом list(), который возвращает список всех категорий в базе данных. Аналогичным способом мы могли бы получить список всех пользователей в базе данных:

Класс ArticleDAO представлен ниже:

Один существующий метод createArticle() хоть и кажется сложным, на самом деле очень простой. Сначала по имени пользователи находится пользователь, а по имени категории - категория. Используя эти два объекта создается и сохраняется в базу данных новый объект Article. Ключевой момент в этом методе строки:

Обязательно необходимо добавить в категорию новый объект Article, иначе связки многие-ко-многим не будет.

Покажем на примере вывод всех категорий и связанных с ними статей и пользователей. Создадим класс CategoryApp:

При выполнении этой программы выводится следующее:

Для демонстрации создания объекта Article создадим класс ArticleApp:

Не забудьте добавить в базу данных категорию с именем "Test category".

Исходный текст программы можно скачать по следующей ссылке - Основы Hibernate

Вроде понятный пример для новичка.
Не могу понять куда конкретно добавить в базу данных категорию с именем "Test category".

Пример 7.1. Hibernate использует свои собственные реализации коллекции.

Постоянные (persistent) коллекции, внедрённые (injected) Hibernate, ведут себя как HashMap , HashSet , TreeMap , TreeSet или ArrayList , в зависимости от типа интерфейса.

Экземпляры коллекций имеют обычное поведение типов значений. Они автоматически сохраняются при обращении к постоянному объекту и автоматически удаляются при отсутствии ссылок. Если коллекция передаётся из одного постоянного объекта в другой, его элементы могут перемещаться из одной таблицы в другую. Две сущности не могут передавать ссылку на один и тот же экземпляр коллекции. Из-за лежащей в основе реляционной модели свойства, содержащие коллекции, не поддерживают семантику значения null. Hibernate не различает ссылку на null и пустую коллекцию.

Заметка

7.2. Как отображать коллекции

Используя аннотации, вы можете отображать Collection , List , Map и Set связанных сущностей, используя @OneToMany и @ManyToMany. Для коллекций базового или встраиваемого типа используйте @ElementCollection. В простейшем случае сопоставление коллекции выглядит следующим образом:

Пример 7.2. Отображение коллекции с использованием @OneToMany и @JoinColumn

Пример 7.3. Отображение коллекции с использованием @OneToMany и @JoinTable

Без описания какого-либо физического отображения (нет @JoinColumn или @JoinTable ) используется однонаправленная один-ко-многим связь с таблицей соединений. Имя таблицы является конкатенацией имени таблицы владельца, _ и имени другой таблицы. Имя (имена) внешнего ключа, ссылающееся на таблицу владельца, представляет собой объединение таблицы владельца, _ и имени столбца первичного ключа владельца. Имя (имена) внешнего ключа, ссылающееся на другую сторону, представляет собой конкатенацию имени свойства владельца, _ и имени столбца первичного ключа другой стороны. Уникальное ограничение (unique constraint) добавляется к внешнему ключу, ссылающемуся на другую таблицу, чтобы отразить один-ко-многим.

Давайте посмотрим, как коллекции отображаются с использованием файлов отображения Hibernate. В этом случае первым шагом является выбор правильного элемента отображения. Это зависит от типа интерфейса. Например, элемент используется для отображения свойств типа Set .

Пример 7.4. Отображение Set с использованием

  • Экземпляр содержащегося класса сущностей не может принадлежать более чем одному экземпляру коллекции.
  • Экземпляр содержащегося класса сущностей не может отображаться более чем на одном значении индекса коллекции.

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

Пример 7.5. Опции элемента

class (обязательный): имя ассоциированного класса.
not-found (необязательный. По умолчанию exception ): указывает, как будут обрабатываться кэшированные идентификаторы, ссылающиеся на отсутствующие записи в бд. ignore будет обрабатывать недостающую строку как ассоциацию null.
entity-name (необязательный): имя сущности ассоциированного класса как альтернатива class .

Элементу не нужно объявлять какие-либо столбцы. Также не обязательно указывать имя table где-либо.

Внимание

. Элемент является репрезентативным:

Пример 7.6. Элементы отображения

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

7.2.1. Сбор внешних ключей

На уровне базы данных коллекция экземпляров различается по внешнему ключу сущности, которому принадлежит коллекция. Этот внешний ключ называется столбцом ключа коллекции или столбцами таблицы коллекции. В столбце ключа коллекции отображается аннотация @JoinColumn , соответственно элемент XML .

Ограничение внешнего ключа может использовать ON DELETE CASCADE . В XML это можно выразить через:

В аннотациях необходимо использовать специальную Hibernate аннотацию @EnDelete.

7.2.2. Индексированные коллекции

В следующих параграфах мы более подробно рассмотрим индексированные коллекции List и Map , как их индекс можно отобразить в Hibernate.

7.2.2.1. Списки (Lists)

Списки могут быть отображены двумя способами:

  • как упорядоченные списки, где порядок не материализован в базе данных
  • как индексированные списки, где порядок материализован в базе данных

Чтобы упорядочить списки в памяти, добавьте @javax.persistence.OrderBy к вашему свойству. Эта аннотация принимает в качестве параметра список свойств, разделённых запятыми (целевой сущности), и соответственно упорядочивает коллекцию (например, firstname asc , age desc , weight asc nulls last ), если строка пуста, коллекция будет упорядочена по первичному ключу целевой сущности.

Пример 7.7. Упорядоченные списки с использованием @OrderBy

Чтобы сохранить значение индекса в выделенном столбце, используйте для вашего свойства аннотацию @javax.persistence.OrderColumn . В этих аннотациях описывается имя столбца и атрибуты столбца, поддерживающие значение индекса. Этот столбец размещается в таблице, содержащей ассоциацию внешнего ключа. Если имя столбца не указано, по умолчанию используется имя свойства по ссылке, за которым следует знак подчеркивания, а затем — ORDER (в следующем примере это будет order_ORDER ).

Пример 7.8. Явный столбец индекса с использованием @OrderColumn

Заметка

Мы рекомендуем вам конвертировать унаследованные (legacy) @org.hibernate.annotations.IndexColumn в стандарт JPA @javax.persistence.OrderColumn . Если вы используете пользовательский список основы индексов (возможно, в настоящее время используется атрибут org.hibernate.annotations.IndexColumn.literal ), вы можете указать это, используя @org.hibernate.annotations.ListIndexBase в сочетании с @javax.persistence.OrderColumn . Основание по умолчанию равно 0, как в Java.

Пример 7.9. Элемент index-list для индексированных коллекций в xml-отображении

column (обязательный): имя столбца, содержащего значения индекса коллекции.
base (необязательный. По умолчанию 0 ): значение столбца индекса, соответствующего первому элементу списка или массива.

Если ваша таблица не имеет столбца индекса, и вы все еще хотите использовать List в качестве типа свойства, вы можете отобразить свойство как Hibernate . bag не сохраняет свой порядок, когда он извлекается из базы данных, но он может быть опционально отсортирован или упорядочен.

7.2.2.2. Карты (Maps)

Вопрос с Картами ( Map ) заключается в том, где хранить ключевое значение. Существует несколько вариантов. Карты могут брать свои ключи от одного из свойств связанных сущностей или иметь выделенные столбцы для хранения явного ключа.

Пример 7.10. Использование целевой сущности в качестве ключа карты через @MapKey

В качестве альтернативы ключ карты отображается на выделенный столбец или столбцы. Чтобы настроить отображение, используйте одну из следующих аннотаций:

  • @MapKeyColumn , если ключ карты является основным типом. Если вы не укажете имя столбца, используется имя свойства, за которым следует символ подчеркивания, за которым следует KEY (например, orders_KEY ).
  • @MapKeyEnumerated / @MapKeyTemporal , если тип ключа карты является соответственно перечислением или датой.
  • @MapKeyJoinColumn / @MapKeyJoinColumns , если тип ключа карты — другая сущность.
  • @AttributeOverride / @AttributeOverrides , когда ключ карты является встраиваемым объектом. Используйте key. как префикс для ваших вложенных имен свойств объекта.

Вы также можете использовать @MapKeyClass для определения типа ключа, если вы не используете generics.

Пример 7.11. Ключ карты как основной тип с использованием @MapKeyColumn

Заметка

Мы рекомендуем вам перейти с @org.hibernate.annotations.MapKey / @org.hibernate.annotation.MapKeyManyToMany на новый стандартный подход, описанный выше.

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

Пример 7.12. map-key xml-элемент отображения

column (необязательный): имя столбца, содержащего значения индекса коллекции.
formula (необязательный): формулу SQL, используемая для вычисления ключа карты.
type (обязательный): тип ключей карты.

Пример 7.13. map-key-many-to-many

column (необязательный): имя столбца внешнего ключа для значений индекса коллекции.
formula (необязательный): формулу SQL, используемая для вычисления внешнего ключа карты.
class (обязательный): класс сущности, используемый в качестве ключа карты.

7.2.3. Коллекции основных типов и встраиваемых объектов

В некоторых ситуациях вам не нужно связывать две сущности, просто создавайте коллекцию базовых типов или встраиваемых объектов. Используйте @ElementCollection для такого случая.

Пример 7.14. Коллекция базовых типов, отображаемых через @ElementCollection

Таблица коллекции, содержащая данные коллекции, устанавливается с помощью аннотации @CollectionTable . Если опущено имя таблицы коллекции, по умолчанию совпадает с конкатенацией имени содержащей сущнсоти и именb атрибута коллекции, разделенным знаком подчеркивания. В нашем примере это будут User_nicknames .

Столбец, содержащий основной тип, устанавливается с помощью аннотации @Column . Если опущено, имя столбца по умолчанию совпадает с именем свойства: в нашем примере это будут nicknames .

Но вы не ограничены основными типами, тип коллекции может быть любым встраиваемым объектом. Чтобы переопределить столбцы встроенного объекта в таблице коллекции, используйте аннотацию @AttributeOverride .

Пример 7.15. @ElementCollection для встраиваемых объектов

Такой встроенный объект не может содержать сам набор.

Заметка

В @AttributeOverride вы должны использовать префикс value. для переопределения свойств встраиваемого объекта, используемого в значении карты и префикс key. для переопределения свойств встраиваемого объекта, используемого в ключе карты.

Заметка

Мы рекомендуем вам перейти от @org.hibernate.annotations.CollectionOfElements к новой аннотации @ElementCollection.

Используя подход с файлом отображения, коллекция значений отображается с использованием тега . Например:

Пример 7.16. Тег для значений коллекции с использованием файлов отображения

column (необязательный): имя столбца, содержащего значения элемента коллекции.
formula (необязательный): формулу SQL, используемая для вычисления элемента.
type (обязательный): тип элемента коллекции.

7.3. Расширенные отображения коллекции

7.3.1. Отсортированные коллекции

Hibernate поддерживает коллекции, реализующие java.util.SortedMap и java.util.SortedSet . С помощью аннотаций вы объявляете компаратор (comparator), используя @Sort . Вы выбрали между типами компараторов: без сортировки (unsorted), естестенная (natural) или пользовательская (custom). Если вы хотите использовать собственную реализацию компаратора, вам также нужно будет указать класс реализации, используя атрибут comparator . Обратите внимание, что вам нужно использовать интерфейс SortedSet или SortedMap .

Пример 7.17. Отсортированная коллекция с @Sort

Используя файлы отображения Hibernate, вы указываете компаратор в файле сопоставления с :

Пример 7.18. Отсортированная коллекция с использованием xml отображения

Совет

Сортированные коллекции фактически ведут себя как java.util.TreeSet или java.util.TreeMap .

Если вы хотите, чтобы сама база данных упорядочивала элементы коллекции, используйте атрибут order-by для отображений set , bag или map . Это решение реализовано с использованием LinkedHashSet или LinkedHashMap и выполняет упорядочение в SQL-запросе, а не в памяти.

Пример 7.19. Сортировка в базе данных с использованием order-by

Заметка

Значение атрибута order-by — это упорядочение SQL, а не HQL-упорядочение.

Ассоциации даже могут быть сортированы по произвольным критериям во время выполнения с использованием filter() :

Пример 7.20. Сортировка через фильтр запроса

7.3.2. Двунаправленные ассоциации

Часто существует ассоциация многие-к-одному, которая является стороной владельца двунаправленных отношений. Соответствующая ассоциация один-ко-многим в этом случае аннотируется @OneToMany(mappedBy=. )

Пример 7.25. Значения по умолчанию для @ManyToMany (однонаправленное)

В качестве таблицы соединений используется Store_City . Столбец Store_id является внешним ключом в таблице Store . Столбец implantedIn_id является внешним ключом таблицы City .

Пример 7.26. Значения по умолчанию для @ManyToMany (двунаправленное)

В качестве таблицы соединений используется Store_Customer . Столбец stores_id является внешним ключом в таблице Store . Столбец customer_id является внешним ключом таблицы Customer .

Заметка

Вы не можете выбрать индексированную коллекцию.

Неинвертированная (non-inverse) сторона используется для сохранения представления в памяти (in-memory) в базу данных.

7.3.3. Двунаправленные ассоциации с индексированными коллекциями

Пример 7.29. Двунаправленная ассоциация с индексированной коллекцией

Пример 7.30. Двунаправленная ассоциация с индексированной коллекцией, но без столбца индекса

Обратите внимание, что в этом отображении конец, связанный с коллекцией, отвечает за обновления внешнего ключа.

7.3.4. Тройные ассоциации

Существует три возможных подхода к отображению тройной ассоциации. Один из подходов — использовать Map с ассоциацией в качестве ее индекса:

Пример 7.31. Отображение тройный ассоциации

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

7.3.5. Использование

Элемент позволяет вам отображать List (или Collection ) с семантикой bag. Например:

имеет синтетический генератор id, как и класс сущности. Каждой строке коллекции присваивается разный суррогатный ключ. Однако Hibernate не предоставляет никакого механизма для обнаружения суррогатного значения ключа для определенной строки.

Эффективность обновления заменяет обычный . Hibernate может эффективно находить отдельные строки и обновлять их или удалять их отдельно, подобно list, map или set.

В текущей реализации стратегия генерации идентификатора native не поддерживается для идентификаторов коллекции .

7.4. Примеры коллекций

В этом разделе рассматриваются примеры коллекций.

Следующий класс имеет коллекцию экземпляров Child :

Пример 7.32. Примеры классов Parent и Child

Это отображает следующие определения таблиц:

Пример 7.35. Определения таблиц для однонаправленного отображения Parent-Child

Обратите внимание на ограничение NOT NULL :

Пример 7.38. Определения таблиц для двунаправленного отображения Parent-Child

В качестве альтернативы, если эта связь должна быть однонаправленной, вы можете применить ограничение NOT NULL .

Пример 7.39. Принудительное ограничение NOT NULL в однонаправленном отношении с использованием аннотаций

Пример 7.40. Принудительное ограничение NOT NULL в однонаправленном отношении с использованием фалов отображений

Аннотации Hibernate в основном делятся на три категории, а именно аннотации на уровне класса, аннотации на уровне атрибутов и аннотации отношений сопоставления.

Аннотация уровня класса

Аннотации уровня класса в основном включают@Entity @Table @Embeddable …

@Entity

Сопоставление класса сущности, класс сущности должен указывать атрибут первичного ключа при его использовании.
@Entity(name = “tableName”)
Атрибут name является необязательным и соответствует таблице в базе данных. Если имя таблицы совпадает с именем класса сущности, его можно не указывать.

@Table

Представляет информацию из таблицы базы данных, соответствующей сущности, используемой вместе с @Entity, и может быть отмечен только в определении класса сущности.
@Table(name = “tableName”)
Имя не является обязательным, что означает имя таблицы сопоставления. Имя таблицы по умолчанию и имя класса одинаковы, и их нужно сформулировать только в том случае, если они не согласованы.

@Embeddable

Указывает, что класс, не являющийся Entity, может быть встроен в другой класс Entity и существовать как свойство. Обычно для создания класса атрибутов извлекают атрибуты, общие для нескольких классов сущностей, и используют аннотацию

Пример использования аннотации класса

Примечание. После использования аннотации необходимо настроить класс в файле конфигурации hibernate.cfg.xml - import javax.persistence.Embeddable; @Embeddable public class Address < private String street; // улица private String houseNum; //Номер дома private String postCode; //Почтовый индекс public String getStreet () < return street; >public void setStreet (String street) < this .street = street; >public String getHouseNum () < return houseNum; >public void setHouseNum (String houseNum) < this .houseNum = houseNum; >public String getPostCode () < return postCode; >public void setPostCode (String postCode) < this .postCode = postCode; >>


Результаты:

Аннотация уровня атрибута

Аннотации на уровне основных атрибутов:@Id @GeneratedValue @GenericGenerator @SequenceGenerator @Column @Embedded @EmbeddedId @Lob @Version @Basic @Transient
@Temporal

Аннотации могут быть помещены в атрибуты, также могут быть размещены в методе get (), но обычно в методе get ()

Примечания, относящиеся к первичному ключу

Укажите первичный ключ класса.Когда класс использует @Entity, эту аннотацию необходимо использовать для указания первичного ключа. Когда класс имеет несколько первичных ключей, класс сущности должен реализовывать сериализуемый интерфейс.

@GeneratedValue

Эта аннотация является необязательной и используется для указания стратегии генерации первичного ключа.
@GeneratedValue(strategy=GenerationType.*,generator=”“)
стратегия представляет стратегию генерации первичного ключа, JPA предоставляет четыре способа:
AUTO : Автоматически выбирается в соответствии с базовой базой данных, значение по умолчанию
IDENTITY : Обеспечивает поддержку встроенных полей идентификации в DB2, MySQL, MS SQL Server, Sybase и HypersonicSQL. Возвращаемый идентификатор имеет тип long, short или int.
SEQUENCE : Используйте Sequence для определения значения первичного ключа, Oracle применяет, нет типа автоинкремента
TABLE : Используйте указанную таблицу для определения значения первичного ключа в сочетании с @TableGenerator

generator Представляет имя генератора первичного ключа, этот атрибут обычно относится к структуре ORM.

Просмотрите часто используемую стратегию генерации первичного ключа Hibernate:
native : Автоматически выбирать в соответствии с возможностями базовой базы данных, использовать метод последовательности для Oracle и использовать идентификацию (механизм генерации самоинкрементного первичного ключа) для MySQL и SQL Server.

assigned : Позвольте приложению назначить идентификатор перед save (), что является стратегией по умолчанию, когда генератор не указан.

increment : Используется для генерации уникального идентификатора для типов long, short или int. При вставке данных Hibernate добавляет первичный ключ с автоинкрементом к первичному ключу, но экземпляр Hibernate поддерживает только один счетчик и не может использоваться в кластере.

identity : Обеспечивает поддержку встроенных полей идентификации в DB2, MySQL, MS SQL Server, Sybase и HypersonicSQL. Возвращаемый идентификатор имеет тип long, short или int.

@GenericGenerator

Использовать с @GeneratedValue
Как использовать:
@GeneratedValue(generator = “generatorName”)
@GenericGenerator(name = “generatorName”, strategy = “”)

Когда первичный ключ имеет тип String, следует использовать назначенную стратегию.
Как использовать

@Id
@GeneratedValue(generator = “assigned”)
@GenericGenerator(name = “assigned”, strategry = “assigned”)

@SequenceGenerator

Объявлена последовательность базы данных
атрибуты:
name: указывает имя стратегии генерации первичного ключа, которое цитируется в атрибуте генератора @GeneratorValue.
sequenceName: указывает имя последовательности базы данных, использованной при создании стратегии.
initialValue: указывает начальное значение первичного ключа, по умолчанию 0
allocationSize: размер каждого значения первичного ключа увеличивается, по умолчанию - 50.

@EmbeddedId

Используйте встроенный класс первичного ключа для получения составного первичного ключа
Примечание. Встроенный первичный ключ должен реализовывать интерфейс Serializable и создаваться общедоступным методом построения без параметров по умолчанию и переопределять методы equals и hashCode.

Не связанный с первичным ключом

@Column

Вы можете сопоставить атрибуты со столбцами и использовать эту аннотацию для переопределения значения по умолчанию. @Column описывает подробное определение поля в таблице базы данных, что очень полезно для инструментов, которые генерируют структуру таблицы базы данных на основе аннотаций JPA.
Общие атрибуты:
name: Необязательно, указывает имя поля в таблице базы данных, значение по умолчанию совпадает с атрибутом
nullable: Необязательно, указывает, разрешено ли поле быть пустым, по умолчанию - true
unique: Указывает, является ли поле уникальным идентификатором, по умолчанию - false
length: Необязательно, с указанием размера поля, действительно только для полей типа String, значение по умолчанию 255
insertable: Необязательный, указывающий, должно ли поле отображаться в инструкции INSERT, когда инфраструктура ORM выполняет операцию вставки, по умолчанию - true
updateable: Необязательно, указывает, должно ли поле отображаться в операторе UPDATA, когда инфраструктура ORM выполняет операцию обновления. По умолчанию - истина. Это свойство очень полезно для полей, которые нельзя изменить после создания, таких как поле дня рождения.

@Embedded

Атрибут аннотации, указывающий, что класс атрибута является встроенным классом
Примечание. Встроенный класс также должен быть аннотирован с помощью @Embeddable

@Version

Используйте эту аннотацию, чтобы добавить поддержку оптимистической блокировки

@Basic

Аннотация отображает атрибут в столбец базы данных. Атрибут представляет собой один неагрегированный тип java. Это аннотация по умолчанию.

Объявить политику доступа
@Basic (fetch = FetchType.EAGER) Получить вовремя (стратегия доступа по умолчанию)
@Basic (fetch = FetchType.LAZY) Отложенная выборка

@Temporal

Используется для определения точности времени, сопоставленной с базой данных
@Temporal (TemporalType = DATE) Дата
@Temporal (TemporalType = TIME) время
@Temporal (TemporalType = TIMESTAMP) оба

@Transient

Указывает, что атрибут не является сопоставлением с полем таблицы базы данных, и инфраструктура ORM проигнорирует этот атрибут. Если атрибут не является сопоставлением полей таблицы базы данных, он должен быть помечен как @Transient, в противном случае структура ORM по умолчанию использует аннотацию @Basic

Указывает, что атрибут сущности является типом большого объекта

Пример использования аннотации атрибута


Результаты:

Сопоставление аннотации отношения

Общая аннотация отношения сопоставления:@OneToOne @OneToMany @ManyToOne @ManyToMany

Определение и аннотация нескольких отношений отображения

Однозначный единый внешний ключ @OneToOne
Однозначное двустороннее связывание внешнего ключа @OneToOne (mappedBy = ”xx”)
Однозначный первичный ключ объединения единого внешнего ключа @Embeddable @EmbeddedId
Связь внешнего ключа "многие к одному" @ManyToOne @JoinColumn
Связь одного внешнего ключа типа "один ко многим" @OneToMany @JoinColumn
Двусторонняя связь внешнего ключа "один ко многим" @ManyToOne @OneToMany @JoinColumn
Связь одного внешнего ключа "многие ко многим" @ManyToMany @JoinTable
Двусторонняя ассоциация внешнего ключа "многие ко многим" @ManyToMany (mappedBy = ”xx”) @JoinTable

Отображение отношений между сущностями

Один к одному: одному гражданину соответствует один идентификационный номер
One-to-many (многие-к-одному): гражданин имеет несколько банковских счетов.
Многие-ко-многим: у одного ученика есть несколько учителей, а у одного учителя - несколько учеников.

Поддержание отношений:
Односторонний: тот, кто управляет отношениями
Двусторонний: обычно управляется несколькими сторонами

Общие атрибуты аннотаций

получить метод загрузки конфигурации
Fetch.EAGER загружается вовремя @ManyToOne. По умолчанию - Fetch.EAGER.
Fetch.LAZY Lazy loading (отложенная загрузка) @OneToMany по умолчанию использует Fetch.LAZY

каскад установить каскадный режим
CascadeType.PERSIST сохранить
CascadeType.REMOVE удалить
CascadeType. Модификация MERGE
CascadeType.REFRESH обновить
CascadeType.ALL все

mappedBy обратной конфигурацией
@OneToOne(mappedBy=”xx”)
эквивалентно инверсному значению истины, что означает отказ от поддержания отношений и управление другой стороной.
xx содержит ссылочное имя обвиняемой стороны как ведущего

@OneToOne

Единая ассоциация внешнего ключа

Настроить аннотации на мастере
@OneToOne(cascade=CascadeType.ALL)
@JoinColumn (name = ”xx”, unique = true) Имя параметра является первичным ключом контролируемого класса, а unique определяет уникальный первичный ключ. xx - первичный ключ управляемого класса и внешний ключ главного класса.

Двойная ассоциация внешнего ключа
Добавьте аннотации, как указано выше, в шаблоне

Примечание к обвиняемому:
@OneToOne (mappedBy = ”xx”) xx - это имя объекта, который мастер держит обвиняемого.

Для двусторонних ассоциаций атрибут mappedBy должен быть установлен, поскольку двусторонние ассоциации могут контролироваться только одной стороной, и невозможно установить внешний ключ для сохранения отношения с обеих сторон, иначе обе стороны не могут сохранить

Пример использования


Результаты:

@OneToMany @ManyToOne

Связь с одним внешним ключом "многие к одному"
Несколько сторон содержат ссылку на одну сторону, например, несколько студентов соответствуют классу

Настройте аннотации для нескольких сторон:
@ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@JoinColumn(name=”xx”,referencedColumnName=”XX”)

Среди них, в @JoinColumn, имя параметра относится к имени столбца внешнего ключа в таблице многопользовательской базы данных, а referencedColumnName относится к имени столбца в таблице базы данных одной стороны, то есть имени столбца первичного ключа. Обычно эти два параметра одинаковы. , По умолчанию это столбец первичного ключа таблицы базы данных.

Один-ко-многим единственная ассоциация внешнего ключа
Одна сторона содержит многостороннюю коллекцию, например класс с несколькими учениками (один ко многим)

Настройте аннотации на одной стороне:
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
@JoinColumn(name=”xx”)

Двунаправленный внешний ключ one-to-many (многие-к-одному)
Многосторонний: многосторонний содержит ссылку на одну сторону.
@ManyToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@JoinColumn(name=”xx”)

Одна партия: одна партия содержит несколько партий.
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
@JoinColumn(name=”xx”)

Примечание: значение атрибута name @JoinColumn в двухсторонней конфигурации должно быть равным, и mappedBy не требуется настраивать в отношениях между двумя сторонами.

Пример использования


Результаты:

@ManyToMany

Один внешний ключ "многие ко многим"
Учащиеся и учителя образуют отношения "многие ко многим"
Одна из нескольких сторон содержит объект коллекции других нескольких сторон (ученик владеет коллекцией учителя)
Создайте промежуточную таблицу и сохраните связь

Настройте аннотации в классе ученика:
@ManyToMany
@JoinTable(name = “teachers_students”,JoinColumns = < @JoinColumn(name = “sid”)>, inverseJoinColumns=<@JoinColumn(name = “tid”)>)

Двусторонний внешний ключ "многие ко многим"
Обе стороны владеют коллекционными объектами друг друга, Одна из сторон должна отказаться от поддержания отношений внешнего ключа.

Настройте аннотации на стороне учителя, и учитель будет держать коллекцию учеников
@ManyToMany(mappedBy=”teachers”)
Значение mappedBy - это имя атрибута коллекции учителей, хранимой учеником.

Настройте, как указано выше, на стороне студента

Пример использования


Результаты:

Обычно при создании проектов необходимо связывать таблицы между собой, это нужно для логической связи объектов между собой. Так как реляционная база данных представляет собой множество взаимосвязанных таблиц, то необходимо уделить отдельное внимание описанию отношений между сущностями с помощью технологии hibernate. Всего существует три основных типа связи: one-to- one, one-to-many, many-to-one; существует также связь many-to-many, но она может быть решена как специальной аннотацией @many-to- many, так и промежуточной таблицей.

Разберем пример. Есть сущность people, которая связана с phone, то есть две таблицы: люди и телефоны. У одного человека может быть несколько телефонов, но не наоборот. Для этого мы создаем связь many-to-one, при этом в таблице phone появится новое поле, ссылающееся на элемент таблицы people, в нем будет храниться идентификатор. Класс people был уже описан ранее, в данном случае он остается неизменным. Класс phone выглядит следующим образом:

  • 1. (©Entity
  • 2. (©Table (name = "phones")
  • 3. public class Phone
  • 4. @Id
  • 5. (©GeneratedValue (strategy = GenerationType.IDENTITY)
  • 6. (©Column (name = "id")
  • 7. private int id;
  • 8. (©Column (name = "number")
  • 9. private String number;
  • 10. (©ManyToOne (targetEntity = People.class, fetch = FetchType.
  • 11. (©JoinColumn (name = "id_poeple")
  • 12. private People people;
  • 13. . (описываем геттеры и сеттер)
  • 14. >

Аннотация (©ManyToOne позволяет создать связь между двумя таблицами, в базе данных данная связь будет выглядеть, как показано на рис. 2.3. Также при использовании связи many-to-one автоматически создается вторичный ключ.

Связь таблиц many-to-one

Рис. 2.3. Связь таблиц many-to-one

Свойство targetEntity указывает, с какой сущностью будет происходить соединение по внешнему ключу.

Свойство fetch (очень важное свойство) может иметь два состояния: LAZY или EAGER — по умолчанию это EAGER. В случае если параметром будет выступать EAGER, связанный элемент будет сразу же подгружаться автоматически. LAZY — пока не обратятся к элементу people, данные не будут загружены.

Ниже показано, как будут формироваться запросы в зависимости от установленного свойства fetch.

При запросе к БД:

  • 1. Phone phone = (Phone) session.createCriteria (Phone.class).add (Restrictions.eq ("id", l)).uniqueResult ();
  • 2. People people = phone.getPeople ();

Простой запрос на получение элемента таблицы телефон и связанного с ним человека.

При выполнении первой строчки будет сформирован запрос на получение данных только о таблице Phone, и только когда идет обращение к связанному объекту People, формируется новый запрос.

  • 1. Hibernate: select this_.id as idl_l_0_, this_.number as number2_l_0_, this_.id_poeple as id_poepl3_l_0_ from phones this_ where this_.id=?
  • 2. Hibernate: select peopleO_.id as idl_0_0_, peopleO_.firstName as firstNam2_0_0_, peopleO_.lastName as lastName3_0_0_, peopleO_.middleName as middleNa4_0_0_, peopleO_.year as year5_0_0_ from people peopleO_ where peopleO_.id = ?

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

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

Пример сформированного запроса:

Hibernate: select this_.id as idl_l_l_, this_.number as number2_l_l_, this_.id_poeple as id_poepl3_l_l_, people2_.id as idl_0_0_, people2_. firstName as firstNam2_0_0_, people2_.lastName as lastName3_0_0_, people2_.middleName as middleNa4_0_0_, people2_.year as year5_0_0_ from phones this_ left outer join people people2_ on this_.id_ poeple=people2_.id where this_.id = ?

Аннотация @JoinColumn в данном случае является не обязательной, она просто содержит параметр, в котором можно указать название колонки.

Часто требуется делать и обратную связь, то есть, имея объект people, получать список связанных с ним телефонов.

Аннотация @OneToMany позволяет осуществить эту мнимую связь, которая обеспечивается hibernate, но не БД. Параметр targetEntity указывает, с какой сущностью идет связь. В параметре mappedBy прописывается имя связующего поля с аннотацией @МапуТоОпе, то есть его имя people. Параметр fetch был ранее описан, в данном случае он играет ту же самую функцию.

Итак, чтобы реализовать эту взаимосвязь, у меня есть 2 подхода. Хотелось бы узнать, какой из них подойдет лучше.

Подход 1 В этом подходе DietPlans таблица будет иметь OneToMany отношения с Owner таблицей и ManyToMany отношения с таблицей клиентов.

А Diet планы были бы следующие -

Клиенту нельзя разрешать создавать какие-либо планы диеты, вместо этого просто подписывайтесь на планы диеты, созданные их владельцем .

Что из 2-х лучше по простоте? Также, если есть лучший способ сделать это моделирование, пожалуйста, дайте мне знать.

Читайте также: