Хибернация за много анотации Урок

1. Въведение

Този бърз урок за хибернация ще ни преведе през пример за картографиране един към много с помощта на JPA анотации, алтернатива на XML.

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

2. Описание

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

Нека да разгледаме следната диаграма на връзката на обекта, за да видим асоциация един към много :

За този пример ще внедрим система за колички, където имаме таблица за всяка количка и друга таблица за всеки артикул. Една количка може да има много артикули, така че тук имаме картографиране един към много .

Начинът, по който това работи на ниво база данни, е, че имаме cart_id като първичен ключ в таблицата на количките, а също и cart_id като външен ключ в елементи .

Начинът, по който го правим в кода, е с @OneToMany .

Нека картографираме класа Cart към обекта Items по начин, който отразява връзката в базата данни:

public class Cart { //... @OneToMany(mappedBy="cart") private Set items; //... }

Също така можем да добавим препратка към Количка в артикули, използвайки @ManyToOne , правейки това двупосочна връзка. Двупосочно означава, че имаме достъп до предмети от колички , а също и до колички от предмети .

В mappedBy Имотът е това, което ние използваме, за да каже на хибернация, които ние използваме променлива да представлява родителския клас в детската нашия клас.

Следните технологии и библиотеки се използват, за да се разработи примерно приложение за хибернация, което реализира асоциация един към много :

  • JDK 1.8 или по-нова версия
  • Хибернация 5
  • Maven 3 или по-нова версия
  • H2 база данни

3. Настройка

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

По-долу е нашият скрипт за база данни за таблици Колички и артикули . Използваме ограничението за външен ключ за картографиране един към много :

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;

Настройката ни за база данни е готова, така че нека да преминем към създаването на примерния проект за хибернация.

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

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

  • Хибернация версия 5 .2.7.Заключителна
  • H2 драйвер версия 1 .4.197

Моля, посетете централното хранилище на Maven за най-новите версии на Hibernate и зависимостите H2.

3.3. Конфигурация на хибернация

Ето конфигурацията на Hibernate:

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

3.4. Клас HibernateAnnotationUtil

С класа HibernateAnnotationUtil просто трябва да се позовем на новия конфигурационен файл на 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 се използва за дефиниране на свойството в клас Items, което ще се използва за картографиране на променливата mappedBy . Ето защо имаме свойство, наречено " количка " в класа 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 () за получаване на Hibernate Session и запазване на обектите на модела в базата данни, реализирайки асоциацията един към много :

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("Cartitem1, Foreign Key Cartitem2, Foreign Key Cartmany-to-one">6. The @ManyToOne Annotation

As we have seen in section 2, we can specify a many-to-one relationship by using the @ManyToOne annotation. A many-to-one mapping means that many instances of this entity are mapped to one instance of another entity – many items in one cart.

The @ManyToOne annotation lets us create bidirectional relationships too. We'll cover this in detail in the next few subsections.

6.1. Inconsistencies and Ownership

Now, if Cart referenced Items, but Items didn't in turn reference Cart, our relationship would be unidirectional. The objects would also have a natural consistency.

In our case though, the relationship is bidirectional, bringing in the possibility of inconsistency.

Let's imagine a situation where a developer wants to add item1 to cart and item2 to cart2, but makes a mistake so that the references between cart2 and item2 become inconsistent:

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!

As shown above, item2 references cart2, whereas cart2 doesn't reference item2, and that's bad.

How should Hibernate save item2 to the database? Will item2 foreign key reference cart1 or cart2?

We resolve this ambiguity using the idea of an owning side of the relationship; references belonging to the owning side take precedence and are saved to the database.

6.2. Items as the Owning Side

As stated in the JPA specification under section 2.9, it's a good practice to mark many-to-one side as the owning side.

In other words, Items would be the owning side and Cart the inverse side, which is exactly what we did earlier.

So how did we achieve this?

By including the mappedBy attribute in the Cart class, we mark it as the inverse side.

At the same time, we also annotate the Items.cart field with @ManyToOne, making Items the owning side.

Going back to our “inconsistency” example, now Hibernate knows that the item2‘s reference is more important and will save item2‘s reference to the database.

Let's check the result:

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

Although cart references item2 in our snippet, item2‘s reference to cart2 is saved in the database.

6.3. Cart as the Owning Side

It's also possible to mark the one-to-many side as the owning side, and many-to-one side as the inverse side.

Although this is not a recommended practice, let's go ahead and give it a try.

The code snippet below shows the implementation of one-to-many side as the owning 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; //.. } 

Notice how we removed the mappedBy element and set the many-to-one @JoinColumn as insertable and updatable to false.

If we run the same code, the result will be the opposite:

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

As shown above, now item2 belongs to cart.

7. Conclusion

We have seen how easy it is to implement the one-to-many relationship with the Hibernate ORM and H2 database using JPA annotations.

Additionally, we learned about bidirectional relationships and how to implement the notion of an owning side.

The source code in this article can be found over on GitHub.