多對一(Many-to-One)映射
多對一(many-to-one)關(guān)聯(lián)是最常見的關(guān)聯(lián)關(guān)系,其中一個對象可以與多個對象相關(guān)聯(lián)。例如,一個相同的地址對象可以與多個雇員的對象相關(guān)聯(lián)。
定義RDBMS表:
考慮一個情況,我們需要員工記錄存儲在EMPLOYEE表,將有以下結(jié)構(gòu):
1
2
3
4
5
6
7
8
|
create table EMPLOYEE ( id INT NOT NULL auto_increment, first_name VARCHAR (20) default NULL , last_name VARCHAR (20) default NULL , salary INT default NULL , address INT NOT NULL , PRIMARY KEY (id) ); |
此外,許多員工都可以有相同的地址,所以這種關(guān)聯(lián)可以使用許多一對一的關(guān)聯(lián)呈現(xiàn)。我們將存儲地址相關(guān)的信息在一個單獨(dú)的表,該表具有以下結(jié)構(gòu):
1
2
3
4
5
6
7
8
|
create table ADDRESS ( id INT NOT NULL auto_increment, street_name VARCHAR (40) default NULL , city_name VARCHAR (40) default NULL , state_name VARCHAR (40) default NULL , zipcode VARCHAR (10) default NULL , PRIMARY KEY (id) ); |
同時創(chuàng)建RBDMS表,并讓他們準(zhǔn)備下一個實(shí)現(xiàn)。
定義POJO類:
讓我們實(shí)現(xiàn)一個POJO類員工將被用于保存與EMPLOYEE表的對象和其地址類型的變量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
import java.util.*; public class Employee{ private int id; private String firstName; private String lastName; private int salary; private Address address; public Employee() {} public Employee(String fname, String lname, int salary, Address address ) { this .firstName = fname; this .lastName = lname; this .salary = salary; this .address = address; } public int getId() { return id; } public void setId( int id ) { this .id = id; } public String getFirstName() { return firstName; } public void setFirstName( String first_name ) { this .firstName = first_name; } public String getLastName() { return lastName; } public void setLastName( String last_name ) { this .lastName = last_name; } public int getSalary() { return salary; } public void setSalary( int salary ) { this .salary = salary; } public Address getAddress() { return address; } public void setAddress( Address address ) { this .address = address; } } |
我們需要定義相應(yīng)的地址表,這樣地址對象可以存儲和檢索到地址表中的另一個POJO類。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
import java.util.*; public class Address{ private int id; private String street; private String city; private String state; private String zipcode; public Address() {} public Address(String street, String city, String state, String zipcode) { this .street = street; this .city = city; this .state = state; this .zipcode = zipcode; } public int getId() { return id; } public void setId( int id ) { this .id = id; } public String getStreet() { return street; } public void setStreet( String street ) { this .street = street; } public String getCity() { return city; } public void setCity( String city ) { this .city = city; } public String getState() { return state; } public void setState( String state ) { this .state = state; } public String getZipcode() { return zipcode; } public void setZipcode( String zipcode ) { this .zipcode = zipcode; } } |
定義Hibernate映射文件:
開發(fā)我們的映射文件,可指示Hibernate如何定義的類映射到數(shù)據(jù)庫表。<many-to-one>進(jìn)行元素將被用來定義規(guī)則建立Employee和Address實(shí)體之間的多對一關(guān)系。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
<? xml version = "1.0" encoding = "utf-8" ?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> < hibernate-mapping > < class name = "Employee" table = "EMPLOYEE" > < meta attribute = "class-description" > This class contains the employee detail. </ meta > < id name = "id" type = "int" column = "id" > < generator class = "native" /> </ id > < property name = "firstName" column = "first_name" type = "string" /> < property name = "lastName" column = "last_name" type = "string" /> < property name = "salary" column = "salary" type = "int" /> < many-to-one name = "address" column = "address" class = "Address" not-null = "true" /> </ class > < class name = "Address" table = "ADDRESS" > < meta attribute = "class-description" > This class contains the address detail. </ meta > < id name = "id" type = "int" column = "id" > < generator class = "native" /> </ id > < property name = "street" column = "street_name" type = "string" /> < property name = "city" column = "city_name" type = "string" /> < property name = "state" column = "state_name" type = "string" /> < property name = "zipcode" column = "zipcode" type = "string" /> </ class > </ hibernate-mapping > |
應(yīng)該保存的映射文件中的格式<classname>.hbm.xml。保存映射文件中的文件Employee.hbm.xml。已經(jīng)熟悉了大部分的映射細(xì)節(jié),但讓我們再次看看映射文件中的所有元素:
映射文檔是具有<hibernate-mapping>為對應(yīng)于每一個類包含2個<class>元素的根元素的XML文檔。
<class>元素被用于定義數(shù)據(jù)庫表從一個Java類特定的映射。 Java類名指定使用class元素的name屬性和使用表屬性數(shù)據(jù)庫表名指定。
<meta>元素是可選元素,可以用來創(chuàng)建類的描述。
<id>元素映射在類中的唯一ID屬性到數(shù)據(jù)庫表的主鍵。 id元素的name屬性是指屬性的類和column屬性是指在數(shù)據(jù)庫表中的列。 type屬性保存了Hibernate映射類型,這種類型的映射將會從Java轉(zhuǎn)換為SQL數(shù)據(jù)類型。
id元素內(nèi)<generator>元素被用來自動生成的主鍵值。將生成元素class屬性設(shè)置為原生讓Hibernate拾取無論是identity,sequence或者h(yuǎn)ilo的算法來創(chuàng)建主鍵根據(jù)底層數(shù)據(jù)庫的支持能力。
<property>元素用于一個Java類的屬性映射到數(shù)據(jù)庫表中的列。元素的name屬性是指屬性的類和column屬性是指在數(shù)據(jù)庫表中的列。 type屬性保存了Hibernate映射類型,這種類型的映射將會從Java轉(zhuǎn)換為SQL數(shù)據(jù)類型。
<many-to-one>進(jìn)行元素是用來設(shè)置EMPLOYEE和地址的實(shí)體之間的關(guān)系。name屬性被設(shè)置為在父類中定義的變量,在我們的情況下,它是地址。列屬性用于在父表EMPLOYEE集的列名。
最后,我們將創(chuàng)建應(yīng)用程序類的main()方法來運(yùn)行應(yīng)用程序。我們將使用這個應(yīng)用程序,以節(jié)省一些employee連同的記錄他們的地址,然后我們將申請CRUD操作上的記錄。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
|
import java.util.*; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class ManageEmployee { private static SessionFactory factory; public static void main(String[] args) { try { factory = new Configuration().configure().buildSessionFactory(); } catch (Throwable ex) { System.err.println( "Failed to create sessionFactory object." + ex); throw new ExceptionInInitializerError(ex); } ManageEmployee ME = new ManageEmployee(); /* Let us have one address object */ Address address = ME.addAddress("Kondapur","Hyderabad","AP","532"); /* Add employee records in the database */ Integer empID1 = ME.addEmployee("Manoj", "Kumar", 4000, address); /* Add another employee record in the database */ Integer empID2 = ME.addEmployee("Dilip", "Kumar", 3000, address); /* List down all the employees */ ME.listEmployees(); /* Update employee's salary records */ ME.updateEmployee(empID1, 5000); /* Delete an employee from the database */ ME.deleteEmployee(empID2); /* List down all the employees */ ME.listEmployees(); } /* Method to add an address record in the database */ public Address addAddress(String street, String city, String state, String zipcode) { Session session = factory.openSession(); Transaction tx = null; Integer addressID = null; Address address = null; try{ tx = session.beginTransaction(); address = new Address(street, city, state, zipcode); addressID = (Integer) session.save(address); tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); }finally { session.close(); } return address; } /* Method to add an employee record in the database */ public Integer addEmployee(String fname, String lname, int salary, Address address){ Session session = factory.openSession(); Transaction tx = null; Integer employeeID = null; try{ tx = session.beginTransaction(); Employee employee = new Employee(fname, lname, salary, address); employeeID = (Integer) session.save(employee); tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); }finally { session.close(); } return employeeID; } /* Method to list all the employees detail */ public void listEmployees( ){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); List employees = session.createQuery("FROM Employee").list(); for (Iterator iterator = employees.iterator(); iterator.hasNext();){ Employee employee = (Employee) iterator.next(); System.out.print("First Name: " + employee.getFirstName()); System.out.print(" Last Name: " + employee.getLastName()); System.out.println(" Salary: " + employee.getSalary()); Address add = employee.getAddress(); System.out.println("Address "); System.out.println(" Street: " + add.getStreet()); System.out.println(" City: " + add.getCity()); System.out.println(" State: " + add.getState()); System.out.println(" Zipcode: " + add.getZipcode()); } tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); }finally { session.close(); } } /* Method to update salary for an employee */ public void updateEmployee(Integer EmployeeID, int salary ){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); Employee employee = (Employee)session.get(Employee.class, EmployeeID); employee.setSalary( salary ); session.update(employee); tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); }finally { session.close(); } } /* Method to delete an employee from the records */ public void deleteEmployee(Integer EmployeeID){ Session session = factory.openSession(); Transaction tx = null ; try { tx = session.beginTransaction(); Employee employee = (Employee)session.get(Employee. class , EmployeeID); session.delete(employee); tx.commit(); } catch (HibernateException e) { if (tx!= null ) tx.rollback(); e.printStackTrace(); } finally { session.close(); } } } |
編譯和執(zhí)行:
下面是步驟來編譯并運(yùn)行上述應(yīng)用程序。請確保已在進(jìn)行的編譯和執(zhí)行之前,適當(dāng)?shù)卦O(shè)置PATH和CLASSPATH。
- 創(chuàng)建hibernate.cfg.xml配置文件中配置章節(jié)解釋。
- 創(chuàng)建Employee.hbm.xml映射文件,如上圖所示。
- 創(chuàng)建Employee.java源文件,如上圖所示,并編譯它。
- 創(chuàng)建Address.java源文件,如上圖所示,并編譯它。
- 創(chuàng)建ManageEmployee.java源文件,如上圖所示,并編譯它。
- 執(zhí)行ManageEmployee二進(jìn)制文件來運(yùn)行程序。
在屏幕上獲得以下結(jié)果,并同時記錄會在員工和地址表創(chuàng)建。
1
|
$java ManageEmployee |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........ First Name: Manoj Last Name: Kumar Salary: 4000 Address Street: Kondapur City: Hyderabad State: AP Zipcode: 532 First Name: Dilip Last Name: Kumar Salary: 3000 Address Street: Kondapur City: Hyderabad State: AP Zipcode: 532 First Name: Manoj Last Name: Kumar Salary: 5000 Address Street: Kondapur City: Hyderabad State: AP Zipcode: 532 |
如果檢查員工和地址表,就應(yīng)該記錄下了:
1
|
mysql> select * from EMPLOYEE; |
1
2
3
4
5
6
|
+----+------------+-----------+--------+---------+ | id | first_name | last_name | salary | address | +----+------------+-----------+--------+---------+ | 1 | Manoj | Kumar | 5000 | 5 | +----+------------+-----------+--------+---------+ 1 row in set (0.00 sec) |
1
|
mysql> select * from ADDRESS; |
1
2
3
4
5
6
|
+----+-------------+-----------+------------+---------+ | id | street_name | city_name | state_name | zipcode | +----+-------------+-----------+------------+---------+ | 1 | Kondapur | Hyderabad | AP | 532 | +----+-------------+-----------+------------+---------+ 1 row in set (0.00 sec) |
一對多(One-to-Many)映射
一對多的映射可以使用一組Java集合不包含任何重復(fù)的元素來實(shí)現(xiàn)。我們已經(jīng)看到了如何設(shè)置映射集合在Hibernate中,所以如果你已經(jīng)學(xué)會了集合(Set)映射,那么所有設(shè)置可用于一對多的映射。
集合被映射到與映射表中<set>元素,并java.util.HashSet中初始化。您可以使用Set集合在類中,有一個集合中不需要重復(fù)的元素。
RDBMS表與POJO類我們依然采用上面例子中定義好的,
定義Hibernate映射文件:
讓我們指示Hibernate如何定義的類映射到數(shù)據(jù)庫表的映射文件。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
<? xml version = "1.0" encoding = "utf-8" ?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> < hibernate-mapping > < class name = "Employee" table = "EMPLOYEE" > < meta attribute = "class-description" > This class contains the employee detail. </ meta > < id name = "id" type = "int" column = "id" > < generator class = "native" /> </ id > < set name = "certificates" cascade = "all" > < key column = "employee_id" /> < one-to-many class = "Certificate" /> </ set > < property name = "firstName" column = "first_name" type = "string" /> < property name = "lastName" column = "last_name" type = "string" /> < property name = "salary" column = "salary" type = "int" /> </ class > < class name = "Certificate" table = "CERTIFICATE" > < meta attribute = "class-description" > This class contains the certificate records. </ meta > < id name = "id" type = "int" column = "id" > < generator class = "native" /> </ id > < property name = "name" column = "certificate_name" type = "string" /> </ class > </ hibernate-mapping > |
應(yīng)該保存的映射文件中的格式<classname>.hbm.xml。我們保存映射文件中的文件Employee.hbm.xml。你已經(jīng)熟悉了大部分的映射細(xì)節(jié),但讓我們再次看看映射文件中的所有元素:
映射文檔是具有<hibernate-mapping>為對應(yīng)于每一個類包含2個<class>元素的根元素的XML文檔。
<class>元素被用于定義數(shù)據(jù)庫表從一個Java類特定的映射。 Java類名指定使用class元素的name屬性和使用表屬性數(shù)據(jù)庫表名指定。
<meta>元素是可選元素,可以用來創(chuàng)建類的描述。
<id>元素映射在類中的唯一ID屬性到數(shù)據(jù)庫表的主鍵。 id元素的name屬性是指屬性的類和column屬性是指在數(shù)據(jù)庫表中的列。 type屬性保存了Hibernate映射類型,這種類型的映射將會從Java轉(zhuǎn)換為SQL數(shù)據(jù)類型。
id元素內(nèi)的<generator>元素被用來自動生成的主鍵值。將生成元素的class屬性設(shè)置為原生讓Hibernate拾取identity,sequence或者h(yuǎn)ilo中的算法來創(chuàng)建主鍵根據(jù)底層數(shù)據(jù)庫的支持能力。
<property>元素用于一個Java類的屬性映射到數(shù)據(jù)庫表中的列。元素的name屬性是指屬性的類和column屬性是指在數(shù)據(jù)庫表中的列。 type屬性保存了Hibernate映射類型,這種類型的映射將會從Java轉(zhuǎn)換為SQL數(shù)據(jù)類型。
<set>元素設(shè)置證書和Employee類之間的關(guān)系。我們使用cascade屬性中<set>元素來告訴Hibernate來保存證書的對象,同時為Employee對象。 name屬性被設(shè)置為在父類中定義的變量集,在我們的例子是證書。對于每一組變量,我們需要定義在映射文件中單獨(dú)的一組元素。
<key>元素是包含外鍵的父對象,即在證書表中的列。表EMPLOYEE。
<one-to-many>元素表示一個Employee對象涉及到很多證書的對象。
創(chuàng)建應(yīng)用程序類:
最后,我們將創(chuàng)建應(yīng)用程序類的main()方法來運(yùn)行應(yīng)用程序。我們將使用這個應(yīng)用程序,以節(jié)省一些員工連同記錄證書,然后我們將應(yīng)用上CRUD操作記錄。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
|
import java.util.*; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.SessionFactory; import org.hibernate.cfg.Configuration; public class ManageEmployee { private static SessionFactory factory; public static void main(String[] args) { try { factory = new Configuration().configure().buildSessionFactory(); } catch (Throwable ex) { System.err.println( "Failed to create sessionFactory object." + ex); throw new ExceptionInInitializerError(ex); } ManageEmployee ME = new ManageEmployee(); /* Let us have a set of certificates for the first employee */ HashSet set1 = new HashSet(); set1.add(new Certificate("MCA")); set1.add(new Certificate("MBA")); set1.add(new Certificate("PMP")); /* Add employee records in the database */ Integer empID1 = ME.addEmployee("Manoj", "Kumar", 4000, set1); /* Another set of certificates for the second employee */ HashSet set2 = new HashSet(); set2.add(new Certificate("BCA")); set2.add(new Certificate("BA")); /* Add another employee record in the database */ Integer empID2 = ME.addEmployee("Dilip", "Kumar", 3000, set2); /* List down all the employees */ ME.listEmployees(); /* Update employee's salary records */ ME.updateEmployee(empID1, 5000); /* Delete an employee from the database */ ME.deleteEmployee(empID2); /* List down all the employees */ ME.listEmployees(); } /* Method to add an employee record in the database */ public Integer addEmployee(String fname, String lname, int salary, Set cert){ Session session = factory.openSession(); Transaction tx = null; Integer employeeID = null; try{ tx = session.beginTransaction(); Employee employee = new Employee(fname, lname, salary); employee.setCertificates(cert); employeeID = (Integer) session.save(employee); tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); }finally { session.close(); } return employeeID; } /* Method to list all the employees detail */ public void listEmployees( ){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); List employees = session.createQuery("FROM Employee").list(); for (Iterator iterator1 = employees.iterator(); iterator1.hasNext();){ Employee employee = (Employee) iterator1.next(); System.out.print("First Name: " + employee.getFirstName()); System.out.print(" Last Name: " + employee.getLastName()); System.out.println(" Salary: " + employee.getSalary()); Set certificates = employee.getCertificates(); for (Iterator iterator2 = certificates.iterator(); iterator2.hasNext();){ Certificate certName = (Certificate) iterator2.next(); System.out.println("Certificate: " + certName.getName()); } } tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); }finally { session.close(); } } /* Method to update salary for an employee */ public void updateEmployee(Integer EmployeeID, int salary ){ Session session = factory.openSession(); Transaction tx = null; try{ tx = session.beginTransaction(); Employee employee = (Employee)session.get(Employee.class, EmployeeID); employee.setSalary( salary ); session.update(employee); tx.commit(); }catch (HibernateException e) { if (tx!=null) tx.rollback(); e.printStackTrace(); }finally { session.close(); } } /* Method to delete an employee from the records */ public void deleteEmployee(Integer EmployeeID){ Session session = factory.openSession(); Transaction tx = null ; try { tx = session.beginTransaction(); Employee employee = (Employee)session.get(Employee. class , EmployeeID); session.delete(employee); tx.commit(); } catch (HibernateException e) { if (tx!= null ) tx.rollback(); e.printStackTrace(); } finally { session.close(); } } } |
編譯和執(zhí)行:
1
|
$java ManageEmployee |
1
2
3
4
5
6
7
8
9
10
11
12
13
|
.......VARIOUS LOG MESSAGES WILL DISPLAY HERE........ First Name: Manoj Last Name: Kumar Salary: 4000 Certificate: MBA Certificate: PMP Certificate: MCA First Name: Dilip Last Name: Kumar Salary: 3000 Certificate: BCA Certificate: BA First Name: Manoj Last Name: Kumar Salary: 5000 Certificate: MBA Certificate: PMP Certificate: MCA |
如果檢查員工和證書表,就應(yīng)該記錄下了:
1
|
mysql> select * from employee; |
1
2
3
4
5
6
|
+----+------------+-----------+--------+ | id | first_name | last_name | salary | +----+------------+-----------+--------+ | 1 | Manoj | Kumar | 5000 | +----+------------+-----------+--------+ 1 row in set (0.00 sec) |
1
|
mysql> select * from certificate; |
1
2
3
4
5
6
7
8
|
+----+------------------+-------------+ | id | certificate_name | employee_id | +----+------------------+-------------+ | 1 | MBA | 1 | | 2 | PMP | 1 | | 3 | MCA | 1 | +----+------------------+-------------+ 3 rows in set (0.00 sec) |