映射一对多关联关系
- 在领域模型中,类与类之间最普遍的关系就是关联关系。
- 在UML中,关联是有方向的。
以Customer
和Order
为例:一个用户能发出多个订单,而一个订单只能属于一个客户,从Order
到Customer
的关联是多对一的关联,而从Customer
到Order
是一对多的关联。
单向n-1
- 单向n-1关联只需从n端可以访问1端。
- 域模型:从
Order
到Customer
的多对一单向关联需要在Order
类中定义一个Customer
属性,而在Customer
类中无需定义存放Order
对象的集合属性。 - 关系数据模型:orders表中的customer_id参照customer表的主键。
- 在Hibernate映射文件中使用
<many-to-one>
标签可以来映射多对一的关联关系,其标签有如下属性:name
:一的那一端的属性的名字class
:一的那一端对应的类名column
:一的那一端在多的一端中对应的数据表中的外键的名字
在此以Order和Customer为例,Order与Customer为多对一关系。首先我们建立Order
类和Customer
类,如下:
package com.cerr.hibernate.n21;
public class Order {
private Integer orderId;
private String orderName;
private Customer customer;
public Integer getOrderId() {
return orderId;
}
public void setOrderId(Integer orderId) {
this.orderId = orderId;
}
public String getOrderName() {
return orderName;
}
public void setOrderName(String orderName) {
this.orderName = orderName;
}
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
package com.cerr.hibernate.n21;
public class Customer {
private Integer customerId;
private String customerName;
public Integer getCustomerId() {
return customerId;
}
public void setCustomerId(Integer customerId) {
this.customerId = customerId;
}
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
}
IDEA只支持由数据表映射出实体类和映射文件,而我们此时是要通过实体类和映射文件来生成数据表,因此映射文件应该我们自己来新建。因此我们新建Customer.hbm.xml
文件和Order.hbm.xml
文件。映射信息如下:Customer.hbm.xml
文件:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!--加入select-before-update="true" -->
<class name="com.cerr.hibernate.n21.Customer" table="customers" schema="hibernate5" dynamic-update="true">
<id name="customerId" column="customer_id">
<generator class="native" />
</id>
<property name="customerName" column="customer_name"/>
</class>
</hibernate-mapping>
Order.hbm.xml
文件:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<!--加入select-before-update="true" -->
<class name="com.cerr.hibernate.n21.Order" table="orders" schema="hibernate5" dynamic-update="true">
<id name="orderId" column="order_id">
<generator class="native" />
</id>
<property name="orderName" column="order_name"/>
<!-- 映射多对一的关联关系 -->
<many-to-one name="customer" class="com.cerr.hibernate.n21.Customer" column="customer_id"></many-to-one>
</class>
</hibernate-mapping>
保存操作的测试类:
package com.cerr.hibernate.n21;
import com.cerr.hibernate.helloworld.News;
import com.cerr.hibernate.helloworld.Pay;
import com.cerr.hibernate.helloworld.Worker;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.jdbc.Work;
import org.junit.After;
import org.junit.Before;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Date;
public class Test {
private SessionFactory sessionFactory;
private Session session;
private Transaction transaction;
@Before
public void init() throws Exception {
Configuration configuration = new Configuration().configure();
sessionFactory = configuration.buildSessionFactory();
session = sessionFactory.openSession();
transaction = session.beginTransaction();
}
@After
public void destory() throws Exception {
transaction.commit();
session.close();
sessionFactory.close();
}
@org.junit.Test
public void test4(){
Customer customer = new Customer();
customer.setCustomerName("aa");
Order order = new Order();
order.setOrderName("1");
Order order1 = new Order();
order1.setOrderName("2");
//设定关联关系
order.setCustomer(customer);
order1.setCustomer(customer);
//先插入1的一端,再插入n的一端。只有三条insert语句。
session.save(customer);
session.save(order);
session.save(order1);
//如果先插入n的一端,再插入1的一端,则会多出来num(n的一端)条update语句。
// session.save(order);
// session.save(order1);
// session.save(customer);
}
}
在测试类中我们分别新建了两个Order
类和一个Customer
类,并且在调用save()
时我们使用了两种情况,一种情况是先保存Customer
类(即先保存1),再保存Order
类(再保存n)。另一种是先保存Order
类(先保存n),再保存Customer
类(再保存1)。两种结果都会插入成功,但是第一种的话只会生成3条INSERT语句,但是第二种会生成3条INSERT语句和2条UPDATE语句。因为先插入n的一端时,无法确定1的一端的外键值,所以只能先进行插入,然后等1的一端插入之后,再额外的发送UPDATE去修改n的一端的外键属性。
所以在插入的时候我们推荐先插入1的那一端,再插入n的那一端。
生成的数据表如下:
![13424350-a7d7b29a2d462300.png](https://upload-images.jianshu.io/upload_images/13424350-a7d7b29a2d462300.png)
customers数据表
![13424350-5635bdd0b8dce144.png](https://upload-images.jianshu.io/upload_images/13424350-5635bdd0b8dce144.png)
orders数据表
查询操作的测试类:
package com.cerr.hibernate.n21;
import com.cerr.hibernate.helloworld.News;
import com.cerr.hibernate.helloworld.Pay;
import com.cerr.hibernate.helloworld.Worker;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.jdbc.Work;
import org.junit.After;
import org.junit.Before;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Date;
public class Test {
private SessionFactory sessionFactory;
private Session session;
private Transaction transaction;
@Before
public void init() throws Exception {
Configuration configuration = new Configuration().configure();
sessionFactory = configuration.buildSessionFactory();
session = sessionFactory.openSession();
transaction = session.beginTransaction();
}
@After
public void destory() throws Exception {
transaction.commit();
session.close();
sessionFactory.close();
}
@org.ju