Hibernate Отношения (один ко многим, многие ко многим, один к одному) - PullRequest
0 голосов
/ 05 апреля 2020

Я работаю над проектом и буду sh реализовывать в нем Hibernate. Я просмотрел много видео, в которых обсуждаются отношения, в которых приводятся примеры, такие как «Заказ клиента», где у клиента может быть много заказов, но заказы относятся только к одному клиенту. Или, Студенты-Курсы, где студенты могут иметь много курсов и наоборот. В моей конкретной ситуации у меня есть таблица Customer и таблица Salutation, где я хочу убедиться, что используется стандартный набор приветствий, поэтому у меня есть следующее:

enter image description here

Я не уверен, как установить этот тип отношений. Во всех примерах, которые я видел, вы бы помещали ссылку на объект приветствия в таблицу Customer, но это, похоже, не имеет смысла. Поле «Приветствие» в моей таблице «Клиенты» имеет тип int. Итак, как вы формируете отношения для таких случаев, как это? Спасибо за вашу помощь!

Ответы [ 2 ]

1 голос
/ 15 апреля 2020

Поскольку вы сказали, что изучаете и не пометили ни одного другого тега, кроме hibernate, например spring или spring-boot, позвольте мне go подробно рассказать о том, как выполнить свою работу.

Давайте рассмотрим пример таблицы Cart and 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;

Если вы используете springboot, вы можете пропустить шаг настройки, так как он предварительно настроен только с одной зависимостью.

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

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

  • Версия Hibernate 5.2.7.Final
  • H2 версия драйвера 1.4.197

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

Конфигурация Hibernate

<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">org.h2.Driver</property>
        <property name="hibernate.connection.password"></property>
        <property name="hibernate.connection.url">
          jdbc:h2:mem:spring_hibernate_one_to_many</property>
        <property name="hibernate.connection.username">sa</property>
        <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
        <property name="hibernate.current_session_context_class">thread</property>
        <property name="hibernate.show_sql">true</property>
    </session-factory>
</hibernate-configuration>

HibernateAnnotationUtil Class

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

Модели

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

@Entity
@Table(name="CART")
public class Cart {
 
    //...
 
    @OneToMany(mappedBy="cart")
    private Set<Items> items;
     
    // getters and setters
}

Обратите внимание, что аннотация @OneToMany используется для определения свойства в классе Items, которое будет использоваться для сопоставления переменной 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
}

в действии

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

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

Аннотация @ManyToOne

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

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

Несоответствия и право собственности

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

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

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

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

Как показано выше, item2 ссылается на cart2, тогда как cart2 не ссылается на item2 - и это плохо.

Как Hibernate должен сохранить item2 в базу данных? Будет ли item2 foreign key ссылаться на cart1 или cart2?

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

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

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

Итак, как мы достигли этого?

Включая атрибут mappedBy в класс Cart, мы помечаем его как обратную сторону.

В то же время мы также аннотируем поле Items.cart с помощью @ManyToOne, делая Предметы стороной-владельцем.

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

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

item1 ID=1, Foreign Key Cart ID=1

item2 ID=2, Foreign Key Cart ID=2

Корзина как сторона-владелец

Это также можно отметить сторону «один ко многим» как сторону-хозяина, а сторону «многие-к-одному» как обратную сторону.

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

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

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<ItemsOIO> items;
    //..
}

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

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

item1 ID=1, Foreign Key Cart ID=1

item2 ID=2, Foreign Key Cart ID=1

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

Надеюсь, этого было достаточно с точки зрения изучения.

0 голосов
/ 09 апреля 2020

Я думаю, вы должны узнать о различного рода отношениях.

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

В моей конкретной ситуации у меня есть таблица Customer и таблица Salutation, где я хочу убедиться, что стандартный набор приветствий

Этот текст, который вы написали, wrotten говорит мне что у вас есть 1 клиент и много возможных приветствий. Если веб-пользователь сможет выбрать только один из них, тогда ваша диаграмма хороша.

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

Существуют отношения «многие ко многим» , но вы не подходите для этого случая.

Вы можете узнать из официальной документации предпочитаемой вами реляционной базы данных. Но основы для понимания есть в SQL руководствах. Мне нравятся эти one или Hibernate one's.

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