一对多与多对一关联
客户(Customer)和订单(Order)的关系:一个客户能发出多个订单,而一个订单只能属于一个客户。从Customer到Order是一对多关联,这意味着每个Order对象都会引用一个Customer对象,因此在Order类中应该定义一个Customer类型的属性,来引用所关联的Customer对象。而从Order到Customer是多对一的关联,这意味着每个Customer对象会引用一组Order对象,因此在Customer类中应该定义一个集合类型的属性,来引用所有关联的Order对象。
如果仅有从Order到Customer的关联,或仅有从Customer到Order的关联,就称为单向关联。如果同时包含两种关联,就称为双向关联。
在关系数据库中,只存在外键参照关系,而且总是由"many"方参照"one"方,这样才能消除数据冗余,因此关系数据库实际上只支持多对一或一对一的双向关联。
customer表结构:
CREATE TABLE customer(
ID NUMBER PRIMARY KEY,
NAME VARCHAR2(20)
);
orders表结构:
CREATE TABLE orders(
ID NUMBER PRIMARY KEY,
order_number VARCHAR2(20),
customer_id NUMBER,
CONSTRAINT fk_customer_id FOREIGN KEY(customer_id) REFERENCES customer(id)
);
-------------------------------------------------------------------
多对一单向关联(Order * <--->Customer 1)
1.xml配置文件方式:
客户实体:
public class Customer {
private Integer id;
private String name;
//对应属性的get/set方法
}
订单实体:
public class Order {
private Integer id;
private String orderNumber;
private Customer customer;
//对应属性的get/set方法
}
***********
Customer.hbm.xml:
***********
Order.hbm.xml:
class="Customer"
cascade="save-update"
/>
**************
-------------------------------------------
2.注解方式:只需要在多的一端Order的属性customer进行注解配置
@Entity
@Table(name="orders") //数据库中的表名为orders,如果数据
库表名和类名相同,可不写
public class Order{
private Integer id;
private String orderNumber;
private Customer customer;
//对应属性的get/set方法
@ManyToOne(cascade=CascadeType.ALL) //多对一关联,Order是多的一方,Customer是一的一方
@JoinColumn(name="customer_id") //指定Order表中生成与Customer对应的字段名(外键,此段代码不写,会自动生成名为customer_id的字段)
public Customer getCustomer(){
return customer;
}
}
测试:
SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
Customer cust = new Customer();
cust.setName("张三");
Order order1 = new Order();
order1.setOrderNumber("1003");
order1.setCustomer(cust);
Order order2 = new Order();
order2.setOrderNumber("1004");
order2.setCustomer(cust);
Session session = sessionFactory.openSession();
//会级联保存和更新对应的Customer对象
session.save(order1);
session.save(order2);
session.beginTransaction().commit();
session.close();
----------------------------------------------------------------------------------
一对多、多对一双向关联
1.xml文件方式:
Order类不变,同上
Customer类,定义一个集合属性,用来存放所有的Order对象:
public class Customer {
private Integer id;
private String name;
private Set
//属性对应的get/set方法
}
在xml中,Order.hbm.xml配置不变,配置"one"的那一端Customer,具体如下:
Customer.hbm.xml
说明:
1)
2)
3)
4)
5)
Hibernate根据以上映射代码获得以下信息:
1)
2)
3)
4)cascade属性取值为"save-update",表明当保存或更新Customer对象时,会级联保存
或更新orders集合中的所有Order对象;
5)在映射一对多的双向关联关系时,应该在"one"的一方把
注意:务必确保在多的一端生成的生成的外键和一的一方生成的外键的名字相同,都为customer_id;如果名字不同则会在多的一端生成多余的外键。
2.注解方式:
Order类的配置不变,在"one"的一端Customer端的orders属性上进行注解配置
@Entity
public class Customer {
private Integer id;
private String name;
private Set
//属性对应的get/set方法
@OneToMany(mappedBy="customer",cascade=CascadeType.ALL)
public Set
return orders;
}
......
}
测试:
SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
Customer cust = new Customer();
cust.setName("张三");
Order order1 = new Order();
order1.setOrderNumber("1003");
Order order2 = new Order();
order2.setOrderNumber("1004");
//建立两个对象的双向关联关系
cust.getOrders().add(order1);
cust.getOrders().add(order2);
order1.setCustomer(cust);
order2.setCustomer(cust);
Session session = sessionFactory.openSession();
//会级联保存和更新对应的Customer和order对象
session.save(cust);
session.beginTransaction().commit();
session.close();
--------------------------------------------------------------------------------------
一对多关联中使用到的注解说明:
1、"一"方:@OneToMany --> mappedBy:"多"方的关联属性
"多"方:@ManyToOne --> @JoinColumn(name="customer_id") : 多方定义的外键字段
2、在双向关联中,有且仅有一段作为主体(owner)端存在:主体端负责维护联接列(即更新),对于不需要维护这种关系的从表则通过mappedBy属性进行声明。mappedBy的值指向另一主体的关联属性。mappedBy相当于inverse="true",inverse=false的一端有责任维护关系,而inverse=true端无须维护这些关系。
3、cascade与fetch使用说明:
cascade属性:是否进行级联保存、更新和删除操作
1)CascadeType.PERSIST (级联保存) 调用persist()方法起作用
2)CascadeType.REMOVE (级联删除) 调用delete()方法
3)CascadeType.REFRESH (级联刷新) 调用refresh()方法
4)CascadeType.MERGE (级联更新) 调用merge()方法
5)CascadeType.ALL (所有操作)
fetch属性:关联关系获取方式,即是否采用延时加载。
1)https://www.wendangku.net/doc/0d4780656.html,ZY(默认值)采用延时加载,查询数据时,不一起查询关联对象的数据。而是当访问关联对象时(如:getOrders()时)才触发相应的查询操作,获取关联对象数据。
2)FetchType.EAGER:是在查询数据时,也直接一起获取关联对象的数据。