Hibernate One To Many Mapping Example Annotation

سنلقي اليوم نظرة على التعيين من واحد إلى العديد في هايبرنيت. سنلقي نظرة على تطبيق التعيين من واحد إلى العديد في هايبرنيت باستخدام التكوين التوضيحي والتكوين عبر XML.

التعيين من واحد إلى العديد في هايبرنيت

ببساطة، التعيين من واحد إلى العديد يعني أن يمكن تعيين صف واحد في جدول إلى صفوف متعددة في جدول آخر. على سبيل المثال، فكر في نظام سلة التسوق حيث لدينا جدول آخر للعناصر. يمكن أن تحتوي السلة على عناصر متعددة، لذا هنا لدينا تعيين من واحد إلى العديد. سنستخدم سيناريو سلة العناصر لتطبيقنا على تعيين هايبرنيت من واحد إلى العديد.

التعيين من واحد إلى العديد في هايبرنيت – إعداد قاعدة البيانات

يمكننا استخدام قيد المفتاح الخارجي للتعيين من واحد إلى العديد. أدناه نص قاعدة بياناتنا لجدول Cart وجدول Items. أنا أستخدم قاعدة بيانات MySQL لتطبيق تعيين هايبرنيت من واحد إلى العديد. setup.sql

CREATE TABLE `Cart` (
  `cart_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `total` decimal(10,0) NOT NULL,
  `name` varchar(10) DEFAULT NULL,
  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,
  `item_id` varchar(10) NOT NULL,
  `item_total` decimal(10,0) NOT NULL,
  `quantity` int(3) 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;

أدناه هو رسم بياني لمخطط ER لجدولي السلة والعناصر. إعداد قاعدة البيانات لدينا جاهز، لننتقل إلى إنشاء مثال مشروع تعيين واحد إلى كثير باستخدام Hibernate. أولاً، سنستخدم تكوين قائم على XML ثم سنقوم بتنفيذ التعيين من واحد إلى كثير باستخدام Hibernate وتعليق JPA.

هيكل مشروع Hibernate One To Many Mapping

قم بإنشاء مشروع Maven بسيط في Eclipse أو المفضل لديك، سيبدو هيكل المشروع النهائي كما في الصورة أدناه.

تبعيات Maven لـ Hibernate

ملف pom.xml النهائي لدينا يحتوي على تبعيات لـ Hibernate وسائق MySQL. Hibernate يستخدم تسجيل JBoss ويتم إضافته تلقائيًا كتبعيات متعددة.

<project xmlns="https://maven.apache.org/POM/4.0.0" xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="https://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.journaldev.hibernate</groupId>
  <artifactId>HibernateOneToManyMapping</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  
  <dependencies>
  	<dependency>
  		<groupId>org.hibernate</groupId>
  		<artifactId>hibernate-core</artifactId>
  		<version>4.3.5.Final</version>
  	</dependency>
  	<dependency>
  		<groupId>mysql</groupId>
  		<artifactId>mysql-connector-java</artifactId>
  		<version>5.0.5</version>
  	</dependency>
  </dependencies>
  
</project>

يرجى ملاحظة أنني استخدم الإصدار الأحدث من Hibernate 4.3.5.Final وإصدار محرك MySQL بناءً على تثبيت قاعدة البيانات الخاصة بي.

طرازات النمذجة الخريطة واحد إلى العديد في Hibernate

لجداولنا Cart و Items، لدينا طرازات نموذجية لتعكسها. Cart.java

package com.journaldev.hibernate.model;

import java.util.Set;

public class Cart {

	private long id;
	private double total;
	private String name;
	private Set<Items> items;
	
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	public double getTotal() {
		return total;
	}
	public void setTotal(double total) {
		this.total = total;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Set<Items> getItems() {
		return items;
	}
	public void setItems(Set<Items> items) {
		this.items = items;
	}
	
}

I am using Set of Items, so that every record is unique. We can also use List or Array for one to many mapping in hibernate. Items.java

package com.journaldev.hibernate.model;

public class Items {

	private long id;
	private String itemId;
	private double itemTotal;
	private int quantity;
	private Cart cart;
	
	//Hibernate يتطلب مُنشئ بدون معلمات
	public Items(){}
	
	public Items(String itemId, double total, int qty, Cart c){
		this.itemId=itemId;
		this.itemTotal=total;
		this.quantity=qty;
		this.cart=c;
	}
	public String getItemId() {
		return itemId;
	}
	public void setItemId(String itemId) {
		this.itemId = itemId;
	}
	public double getItemTotal() {
		return itemTotal;
	}
	public void setItemTotal(double itemTotal) {
		this.itemTotal = itemTotal;
	}
	public int getQuantity() {
		return quantity;
	}
	public void setQuantity(int quantity) {
		this.quantity = quantity;
	}
	public Cart getCart() {
		return cart;
	}
	public void setCart(Cart cart) {
		this.cart = cart;
	}
	public long getId() {
		return id;
	}
	public void setId(long id) {
		this.id = id;
	}
	
}

تحتوي العناصر على علاقة كثير إلى واحد مع السلة، لذا لا نحتاج إلى مجموعة لكائن Cart.

فئة الأداة SessionFactory في Hibernate

لدينا فئة أداة لإنشاء SessionFactory في Hibernate. HibernateUtil.java

package com.journaldev.hibernate.util;

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

public class HibernateUtil {

	private static SessionFactory sessionFactory;
	
	private static SessionFactory buildSessionFactory() {
        try {
            // إنشاء SessionFactory من hibernate.cfg.xml
        	Configuration configuration = new Configuration();
        	configuration.configure("hibernate.cfg.xml");
        	System.out.println("Hibernate Configuration loaded");
        	
        	ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
        	System.out.println("Hibernate serviceRegistry created");
        	
        	SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        	
            return sessionFactory;
        }
        catch (Throwable ex) {
            System.err.println("Initial SessionFactory creation failed." + ex);
            ex.printStackTrace();
            throw new ExceptionInInitializerError(ex);
        }
    }
	
	public static SessionFactory getSessionFactory() {
		if(sessionFactory == null) sessionFactory = buildSessionFactory();
        return sessionFactory;
    }
}

ملف تكوين XML الخاص بـ Hibernate

يحتوي ملف تكوين Hibernate xml الخاص بنا على معلومات قاعدة البيانات وتفاصيل مصدر الخريطة. hibernate.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
		"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
		"https://hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.password">pankaj123</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost/TestDB</property>
        <property name="hibernate.connection.username">pankaj</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        
        <property name="hibernate.current_session_context_class">thread</property>
        <property name="hibernate.show_sql">true</property>
        
        <mapping resource="cart.hbm.xml"/>
        <mapping resource="items.hbm.xml"/>
    </session-factory>
</hibernate-configuration>

مثال تعيين واحد إلى كثير – تكوين XML للهايبرنيت

هذا هو الجزء الأكثر أهمية من البرنامج التعليمي، دعنا نرى كيف يجب علينا تعيين كل من فئتي Cart و Items لتعيين واحد إلى كثير في الهايبرنيت. cart.hbm.xml

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"https://hibernate.org/dtd/hibernate-mapping-3.0.dtd">
	
<hibernate-mapping package="com.journaldev.hibernate.model">
	<class name="Cart" table="CART" >
		<id name="id" type="long">
			<column name="cart_id" />
			<generator class="identity" />
		</id>
		<property name="total" type="double">
			<column name="total" />
		</property>
		<property name="name" type="string">
			<column name="name" />
		</property>
		<set name="items" table="ITEMS" fetch="select">
			<key>
				<column name="cart_id" not-null="true"></column>
			</key>
			<one-to-many class="Items"/>
		</set>
	</class>
	
</hibernate-mapping>

الجزء المهم هو عنصر set وعنصر one-to-many داخله. لاحظ أننا نقدم مفتاحًا يجب استخدامه لتعيين واحد إلى كثير، أي cart_id. items.hbm.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
"https://hibernate.org/dtd/hibernate-mapping-3.0.dtd" >

<hibernate-mapping package="com.journaldev.hibernate.model">

	<class name="Items" table="ITEMS">
		<id name="id" type="long">
			<column name="id" />
			<generator class="identity" />
		</id>
		<property name="itemId" type="string">
			<column name="item_id"></column>
		</property>
		<property name="itemTotal" type="double">
			<column name="item_total"></column>
		</property>
		<property name="quantity" type="integer">
			<column name="quantity"></column>
		</property>
		
		<many-to-one name="cart" class="Cart">
			<column name="cart_id" not-null="true"></column>
		</many-to-one>
	</class>

</hibernate-mapping>

لاحظ أنه من العناصر إلى السلة، فإنها علاقة كثير إلى واحد. لذا نحتاج إلى استخدام عنصر many-to-one للسلة ونقدم اسم العمود الذي سيتم تعيينه بالمفتاح. بناءً على تكوين تعيين الهايبرنيت للسلة، سيتم استخدام مفتاحها cart_id للتعيين. مشروعنا لمثال تعيين واحد إلى كثير باستخدام تعيين XML جاهز، دعونا نكتب برنامج اختبار ونتحقق مما إذا كان يعمل بشكل صحيح أم لا.

مثال تعيين واحد إلى كثير – برنامج الاختبار

HibernateOneToManyMain.java

package com.journaldev.hibernate.main;

import java.util.HashSet;
import java.util.Set;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

import com.journaldev.hibernate.model.Cart;
import com.journaldev.hibernate.model.Items;
import com.journaldev.hibernate.util.HibernateUtil;

public class HibernateOneToManyMain {

	public static void main(String[] args) {

		Cart cart = new Cart();
		cart.setName("MyCart");
		
		Items item1 = new Items("I1", 10, 1, cart);
		Items item2 = new Items("I2", 20, 2, cart);
		Set itemsSet = new HashSet();
		itemsSet.add(item1); itemsSet.add(item2);
		
		cart.setItems(itemsSet);
		cart.setTotal(10*1 + 20*2);
		
		SessionFactory sessionFactory = null;
		Session session = null;
		Transaction tx = null;
		try{
		//احصل على الجلسة
		sessionFactory = HibernateUtil.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());
		
		}catch(Exception e){
			System.out.println("Exception occured. "+e.getMessage());
			e.printStackTrace();
		}finally{
			if(!sessionFactory.isClosed()){
				System.out.println("Closing SessionFactory");
				sessionFactory.close();
			}
		}
	}

}

يرجى ملاحظة أنه يجب علينا حفظ كل من كائنات السلة والعناصر واحدة تلو الأخرى. ستقوم Hibernate بالعناية بتحديث المفاتيح الخارجية في جدول العناصر. عند تنفيذ البرنامج أعلاه، نحصل على الإخراج التالي.

Hibernate Configuration loaded
Hibernate serviceRegistry created
Session created
Hibernate: insert into CART (total, name) values (?, ?)
Hibernate: insert into ITEMS (item_id, item_total, quantity, cart_id) values (?, ?, ?, ?)
Hibernate: insert into ITEMS (item_id, item_total, quantity, cart_id) values (?, ?, ?, ?)
Hibernate: update ITEMS set cart_id=? where id=?
Hibernate: update ITEMS set cart_id=? where id=?
Cart ID=6
Closing SessionFactory

يرجى ملاحظة أن Hibernate يستخدم استعلام التحديث لتعيين معرف السلة في جدول العناصر.

تعيين Hibernate One To Many Mapping Annotation

الآن بعد أن رأينا كيفية تنفيذ التعيين One To Many في Hibernate باستخدام تكوينات XML، دعونا نرى كيف يمكننا القيام بنفس الشيء باستخدام تعليقات JPA.

مثال تعيين Hibernate One To Many Annotation

ملف تكوين Hibernate متقريبًا متماثل، باستثناء تغيير عنصر التعيين لأننا نستخدم الفئات لتعيين Hibernate One To Many باستخدام التعليق. hibernate-annotation.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
		"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
		"https://hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.password">pankaj123</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost/TestDB</property>
        <property name="hibernate.connection.username">pankaj</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
        
        <property name="hibernate.current_session_context_class">thread</property>
        <property name="hibernate.show_sql">true</property>
        
        <mapping class="com.journaldev.hibernate.model.Cart1"/>
        <mapping class="com.journaldev.hibernate.model.Items1"/>
    </session-factory>
</hibernate-configuration>

فئة الأداة لمصنع Hibernate SessionFactory

فئة الأداة لمصنع SessionFactory تقريبًا متطابقة، نحتاج فقط إلى استخدام ملف تكوين Hibernate الجديد. HibernateAnnotationUtil.java

package com.journaldev.hibernate.util;

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

public class HibernateAnnotationUtil {

	private static SessionFactory sessionFactory;
	
	private static SessionFactory buildSessionFactory() {
        try {
            // إنشاء SessionFactory من ملف hibernate-annotation.cfg.xml
        	Configuration configuration = new Configuration();
        	configuration.configure("hibernate-annotation.cfg.xml");
        	System.out.println("Hibernate Annotation Configuration loaded");
        	
        	ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
        	System.out.println("Hibernate Annotation serviceRegistry created");
        	
        	SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        	
            return sessionFactory;
        }
        catch (Throwable ex) {
            System.err.println("Initial SessionFactory creation failed." + ex);
            ex.printStackTrace();
            throw new ExceptionInInitializerError(ex);
        }
    }
	
	public static SessionFactory getSessionFactory() {
		if(sessionFactory == null) sessionFactory = buildSessionFactory();
        return sessionFactory;
    }
}

فئات نموذج التعليم الواحد إلى العديد في التعليق الخريطة بواسطة التعليق

نظرًا لعدم وجود ملفات تعيين قائمة على الـ xml، سيتم إجراء جميع تكوينات الخريطة المتعلقة باستخدام تعليقات JPA في فئات النموذج. إذا فهمت تعيين القائمة على الـ xml، فإنه بسيط جدًا ومشابه. Cart1.java

package com.journaldev.hibernate.model;

import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;

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

	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name="cart_id")
	private long id;
	
	@Column(name="total")
	private double total;
	
	@Column(name="name")
	private String name;
	
	@OneToMany(mappedBy="cart1")
	private Set items1;
	
// طرق Getter Setter للخصائص
}

النقطة المهمة للملاحظة هي تعليق OneToMany حيث يتم استخدام المتغير mappedBy لتحديد الخاصية في فئة Items1 التي سيتم استخدامها لأغراض الخريطة. لذا يجب أن يكون لدينا خاصية تسمى “cart1” في فئة Items1. لا تنس تضمين جميع طرق Getter-Setter. Items1.java

package com.journaldev.hibernate.model;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name="ITEMS")
public class Items1 {

	@Id
	@GeneratedValue(strategy=GenerationType.IDENTITY)
	@Column(name="id")
	private long id;
	
	@Column(name="item_id")
	private String itemId;
	
	@Column(name="item_total")
	private double itemTotal;
	
	@Column(name="quantity")
	private int quantity;
	
	@ManyToOne
	@JoinColumn(name="cart_id", nullable=false)
	private Cart1 cart1;
	
	// Hibernate يتطلب مُنشئًا بدون معلمات
	public Items1(){}
	
	public Items1(String itemId, double total, int qty, Cart1 c){
		this.itemId=itemId;
		this.itemTotal=total;
		this.quantity=qty;
		this.cart1=c;
	}
// طرق Getter Setter
}

أهم نقطة في الفئة أعلاه هي التعليق ManyToOne على متغير فئة Cart1 وتعليق JoinColumn لتحديد اسم العمود للتعيين. هذا هو كل شيء بالنسبة للتعيين من واحد إلى كثير في هايبرنيت باستخدام التعليق في فئات النموذج. قارنها مع تكوينات XML، ستجدها متشابهة جدًا. دعونا نكتب برنامج اختبار ونقوم بتنفيذه.

برنامج اختبار مثال التعيين من واحد إلى كثير في هايبرنيت بتعليق

برنامج الاختبار لدينا مشابه تمامًا لتكوين ال XML، نستخدم فقط الفئات الجديدة للحصول على جلسة هايبرنيت وحفظ كائنات النموذج في قاعدة البيانات. HibernateOneToManyAnnotationMain.java

package com.journaldev.hibernate.main;

import java.util.HashSet;
import java.util.Set;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

import com.journaldev.hibernate.model.Cart1;
import com.journaldev.hibernate.model.Items1;
import com.journaldev.hibernate.util.HibernateAnnotationUtil;

public class HibernateOneToManyAnnotationMain {

	public static void main(String[] args) {

		Cart1 cart = new Cart1();
		cart.setName("MyCart1");
		
		Items1 item1 = new Items1("I10", 10, 1, cart);
		Items1 item2 = new Items1("I20", 20, 2, cart);
		Set itemsSet = new HashSet();
		itemsSet.add(item1); itemsSet.add(item2);
		
		cart.setItems1(itemsSet);
		cart.setTotal(10*1 + 20*2);
		
		SessionFactory sessionFactory = null;
		Session session = null;
		Transaction tx = null;
		try{
		//الحصول على الجلسة
		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("Cart1 ID="+cart.getId());
		System.out.println("item1 ID="+item1.getId()+", Foreign Key Cart ID="+item1.getCart1().getId());
		System.out.println("item2 ID="+item2.getId()+", Foreign Key Cart ID="+item1.getCart1().getId());
		
		}catch(Exception e){
			System.out.println("Exception occured. "+e.getMessage());
			e.printStackTrace();
		}finally{
			if(!sessionFactory.isClosed()){
				System.out.println("Closing SessionFactory");
				sessionFactory.close();
			}
		}
	}

}

عند تنفيذ برنامج الاختبار أعلاه لتعيين واحد إلى كثير باستخدام التعليق، نحصل على الناتج التالي.

Hibernate Annotation Configuration loaded
Hibernate Annotation serviceRegistry created
Session created
Hibernate: insert into CART (name, total) values (?, ?)
Hibernate: insert into ITEMS (cart_id, item_id, item_total, quantity) values (?, ?, ?, ?)
Hibernate: insert into ITEMS (cart_id, item_id, item_total, quantity) values (?, ?, ?, ?)
Cart1 ID=7
item1 ID=9, Foreign Key Cart ID=7
item2 ID=10, Foreign Key Cart ID=7
Closing SessionFactory

هذا كل شيء بالنسبة لتعيين واحد إلى كثير في هايبرنيت، قم بتنزيل المشروع العيني من الرابط أدناه وقم بإجراء المزيد من التجارب.

تنزيل مشروع Hibernate OneToMany Mapping

Source:
https://www.digitalocean.com/community/tutorials/hibernate-one-to-many-mapping-annotation