Рубрики
Без рубрики

Спящий режим Один ко многим Учебник по аннотациям

В этом уроке мы рассмотрим сопоставление “один ко многим” с использованием аннотаций JPA на практическом примере.

Автор оригинала: baeldung.

1. введение

В этом кратком учебнике по гибернации мы рассмотрим пример сопоставления один ко многим с использованием аннотаций JPA, альтернативного XML.

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

Дальнейшее чтение:

Весенняя загрузка с гибернацией

Обзор идентификаторов в Hibernate/JPA

2. Описание

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

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

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

Как это работает на уровне базы данных, у нас есть cart_id в качестве первичного ключа в таблице cart , а также cart_id в качестве внешнего ключа в items .

Мы делаем это в коде с помощью @OneToMany .

Давайте сопоставим класс Cart с объектом Items таким образом, чтобы он отражал отношения в базе данных:

public class Cart {

    //...     
 
    @OneToMany(mappedBy="cart")
    private Set items;
	
    //...
}

Мы также можем добавить ссылку на Корзину в Элементы используя @ManyToOne , делая это двунаправленным отношением. Двунаправленный означает, что мы можем получить доступ к предметам из тележек , а также тележкам из предметов .

Свойство mappedBy – это то, что мы используем, чтобы сообщить Hibernate, какую переменную мы используем для представления родительского класса в нашем дочернем классе.

Следующие технологии и библиотеки используются для разработки примера приложения Hibernate, реализующего ассоциацию один ко многим :

  • JDK 1.8 или более поздняя версия
  • Спящий режим 5
  • Maven 3 или более поздняя версия
  • База данных H2

3. Настройка

3.1. Настройка базы данных

Ниже приведен наш скрипт базы данных для таблиц Cart и Items . Мы используем ограничение внешнего ключа для сопоставления один ко многим :

CREATE TABLE `Cart` (
  `cart_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  PRIMARY KEY (`cart_id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;

CREATE TABLE `Items` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `cart_id` int(11) unsigned NOT NULL,
  PRIMARY KEY (`id`),
  KEY `cart_id` (`cart_id`),
  CONSTRAINT `items_ibfk_1` FOREIGN KEY (`cart_id`) REFERENCES `Cart` (`cart_id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

Наша настройка базы данных готова, поэтому давайте перейдем к созданию примера проекта Hibernate.

3.2. Зависимости Maven

Затем мы добавим зависимости драйверов Hibernate и H2 в ваш pom.xml файл. Зависимость Hibernate использует ведение журнала JBoss, и она автоматически добавляется в качестве транзитивных зависимостей:

  • Гибернация версии 5 .2.7.Финал
  • Драйвер H2 версии 1 .4.197

Пожалуйста, посетите центральный репозиторий Maven для получения последних версий Hibernate и зависимостей H2 .

3.3. Настройка режима гибернации

Вот конфигурация гибернации:


    
        org.h2.Driver
        
        
          jdbc:h2:mem:spring_hibernate_one_to_many
        sa
        org.hibernate.dialect.H2Dialect
        thread
        true
    

3.4. Класс Util аннотации Hibernate

С помощью класса Hibernate Annotation Util нам просто нужно сослаться на новый файл конфигурации Hibernate:

private static SessionFactory sessionFactory;

private SessionFactory buildSessionFactory() {
     
    ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().
      configure("hibernate-annotation.cfg.xml").build();
    Metadata metadata = new MetadataSources(serviceRegistry).getMetadataBuilder().build();
    SessionFactory sessionFactory = metadata.getSessionFactoryBuilder().build();
        	
    return sessionFactory;
}	

public SessionFactory getSessionFactory() {
    if(sessionFactory == null) sessionFactory = buildSessionFactory();
    return sessionFactory;
}

4. Модели

Конфигурации, связанные с отображением, будут выполняться с использованием аннотаций JPA в классах моделей:

@Entity
@Table(name="CART")
public class Cart {

    //...

    @OneToMany(mappedBy="cart")
    private Set items;
	
    // getters and setters
}

Обратите внимание, что аннотация @OneToMany используется для определения свойства в Элементы класса, которые будут использоваться для сопоставления переменной mappedBy . Вот почему у нас есть свойство с именем ” cart ” в классе Items :

@Entity
@Table(name="ITEMS")
public class Items {
    
    //...
    @ManyToOne
    @JoinColumn(name="cart_id", nullable=false)
    private Cart cart;

    public Items() {}
    
    // getters and setters
}

Также важно отметить, что аннотация @ManyToOne связана с переменной класса Cart . @JoinColumn аннотация ссылается на сопоставленный столбец.

5. В действии

В тестовой программе мы создаем класс с методом main () для получения сеанса гибернации и сохранения объектов модели в базе данных, реализующей ассоциацию один ко многим :

sessionFactory = HibernateAnnotationUtil.getSessionFactory();
session = sessionFactory.getCurrentSession();
System.out.println("Session created");
	    
tx = session.beginTransaction();

session.save(cart);
session.save(item1);
session.save(item2);
	    
tx.commit();
System.out.println("Cart ID=" + cart.getId());
System.out.println("item1 ID=" + item1.getId()
  + ", Foreign Key Cart ID=" + item.getCart().getId());
System.out.println("item2 ID=" + item2.getId()
+ ", Foreign Key Cart ID=" + item.getCart().getId());

Это результат нашей тестовой программы:

Session created
Hibernate: insert into CART values ()
Hibernate: insert into ITEMS (cart_id)
  values (?)
Hibernate: insert into ITEMS (cart_id)
  values (?)
Cart ID=7
item1 ID=11, Foreign Key Cart ID=7
item2 ID=12, Foreign Key Cart ID=7
Closing SessionFactory

6. Аннотация @ManyToOne

Как мы видели в разделе 2, мы можем указать отношение многие к одному , используя аннотацию @ManyToOne . Сопоставление многие к одному означает, что многие экземпляры этой сущности сопоставляются с одним экземпляром другой сущности – много элементов в одной корзине .

Аннотация @ManyToOne также позволяет создавать двунаправленные отношения. Мы подробно рассмотрим это в следующих нескольких подразделах.

6.1. Несоответствия и Право собственности

Теперь, если Корзина ссылка Пункты , но Элементы в свою очередь не ссылались на диаграмму , наши отношения были бы однонаправленными . Объекты также будут иметь естественную согласованность.

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

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

Cart cart1 = new Cart();
Cart cart2 = new Cart();

Items item1 = new Items(cart1);
Items item2 = new Items(cart2); 
Set itemsSet = new HashSet();
itemsSet.add(item1);
itemsSet.add(item2); 
cart1.setItems(itemsSet); // wrong!

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

Как Hibernate должен сохранять item2 в базе данных? Будет item2 ссылка на внешний ключ card1 или card2 ?

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

6.2. Предметы в качестве Стороны-владельца

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

Другими словами, I tems будет стороной владельца и Cart обратной стороной, что именно то, что мы делали ранее.

Так как же мы этого добились?

Путем включения mappedBy атрибут в Тележка класс, мы отмечаем его как обратную сторону.

В то же время мы также комментируем Предметы. корзина поле с @ManyToOne , изготовление Предметы сторона собственника.

Возвращаясь к нашему примеру “несогласованности”, теперь Hibernate знает, что ссылка item 2 более важна и сохранит ссылку item2 в базе данных.

Давайте проверим результат:

item1 ID=1, Foreign Key Cart ID=1
item2 ID=2, Foreign Key Cart ID=2

Хотя корзина ссылки пункт 2 в нашем фрагменте, пункт 2 ссылка на корзину 2 сохраняется в базе данных.

6.3. Тележка как Сторона-владелец

Также можно пометить сторону один ко многим как сторону владельца, а сторону много к одному как обратную сторону.

Хотя это не рекомендуется, давайте попробуем.

В приведенном ниже фрагменте кода показана реализация one-to-many side в качестве стороны-владельца:

public class ItemsOIO {
    
    //  ...
    @ManyToOne
    @JoinColumn(name = "cart_id", insertable = false, updatable = false)
    private CartOIO cart;
    //..
}

public class CartOIO {
    
    //..  
    @OneToMany
    @JoinColumn(name = "cart_id") // we need to duplicate the physical information
    private Set items;
    //..
}

Обратите внимание, как мы удалили элемент mappedBy и установили many-to-one @JoinColumn как вставляемый и обновляемый в false .

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

item1 ID=1, Foreign Key Cart ID=1
item2 ID=2, Foreign Key Cart ID=1

Как показано выше, теперь пункт 2 принадлежит корзине.

7. Заключение

Мы видели, как легко реализовать связь один ко многим с базой данных Hibernate ORM и H2 с помощью аннотаций JPA.

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

Исходный код в этой статье можно найти на GitHub .