Hibernate深入理解----04关联关系(单向多对1,双向1对多)
来源:程序员人生 发布时间:2016-10-17 15:44:53 阅读次数:2367次
参考代码下载github:https://github.com/changwensir/java-ee/tree/master/hibernate4
•在领域模型中, 类与类之间最普遍的关系就是关联关系.在UML图中,关联是有方向的
1.单向多对1
两个类,多个Order对应1个Customer
public class Customer {
private Integer customerId;
private String customerName;
//省去get,set方法
}
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping⑶.0.dtd">
<hibernate-mapping package="com.changwen.hibernate4.mapped.manyToOne.pojo">
<class name="Customer" table="customers">
<id name="customerId" column="customer_id" type="java.lang.Integer">
<generator class="native" />
</id>
<property name="customerName" column="customer_name" type="java.lang.String"/>
</class>
</hibernate-mapping>
Order类
public class Order {
private Integer orderId;
private String orderName;
private Customer customer;
//省去get,set方法
}
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping⑶.0.dtd">
<hibernate-mapping package="com.changwen.hibernate4.mapped.manyToOne.pojo">
<class name="Order" table="orders">
<id name="orderId" type="java.lang.Integer">
<column name="order_id" />
<generator class="native" />
</id>
<property name="orderName" type="java.lang.String">
<column name="order_name" />
</property>
<!--多个Order对应1个Customer
映照多对1的关联关系。 使用 many-to-one 来映照多对1的关联关系
name: 多对1端关联的1那真个属性的名字
class: 1那真个属性对应的类名
column: 1那端在多的1端对应的数据表中的外键的名字,随便取
-->
<many-to-one name="customer" class="Customer" column="customer_ID"/>
</class>
</hibernate-mapping>
然后把两个hbm.xml映照到cfg.xml里
测试:before,after的见前面的内容
@Test
public void testMany2OneSave(){
Customer customer = new Customer();
customer.setCustomerName("BB");
Order order1 = new Order();
order1.setOrderName("ORDER⑶");
Order order2 = new Order();
order2.setOrderName("ORDER⑷");
//设定关联关系
order1.setCustomer(customer);
order2.setCustomer(customer);
//这类写法更好
//履行 save 操作: 先插入 Customer, 再插入 Order, 3 条 INSERT
//先插入 1 的1端, 再插入 n 的1端, 只有 INSERT 语句.
//推荐先插入 1 的1端, 后插入 n 的1端
session.save(customer);
session.save(order1);
session.save(order2);
//先插入 Order, 再插入 Customer. 3 条 INSERT, 2 条 UPDATE
//先插入 n 的1端, 再插入 1 的1端, 会多出 UPDATE 语句!
//由于在插入多的1端时, 没法肯定 1 的1真个外键值. 所以只能等 1 的1端插入后, 再额外发送 UPDATE 语句.
/* sessionPojo.save(order1);
sessionPojo.save(order2);
sessionPojo.save(customer);*/
}
@Test
public void testMany2OneGet(){
//结论1. 若查询多的1真个1个对象, 则默许情况下, 只查询了多的1真个对象.
// 而没有查询关联的1 的那1真个对象!
// Order order = (Order) sessionPojo.get(Order.class, 8);
// System.out.println(order.getOrderName());
//结论2. 在需要使用到关联的对象时, 才发送对应的 SQL 语句.
// Customer customer = order.getCustomer();
// System.out.println(customer.getCustomerName());
//上面1,2的输出结果顺序是:sql语句-->sout-->sql语句-->sout
//3. 在查询 Customer 对象时, 由多的1端导航到 1 的1端时,
//若此时 sessionPojo 已被关闭, 则默许情况下会产生 LazyInitializationException 异常
// Order order2 = (Order) session.get(Order.class, 8);
// System.out.println(order2.getOrderName());
// session.close(); //这里测试时需要把destory()方法里的transaction和session注解掉
// Customer customer2 = order2.getCustomer();
// System.out.println(customer2.getCustomerName());
//上面3的输出结果顺序是:sql语句-->order2.getOrderName()-->异常
//4. 获得 Order 对象时, 默许情况下, 其关联的 Customer 对象是1个代理对象!
Order order3 = (Order) session.get(Order.class, 8);
System.out.println(order3.getCustomer().getClass().getName());
}
@Test
public void testDelete(){
//在不设定级联关系的情况下, 且 1 这1真个对象有 n 的对象在援用, 不能直接删除 1 这1真个对象
Customer customer = (Customer) session.get(Customer.class, 8);
session.delete(customer); //不能删除
}
@Test
public void testUpdate(){
Order order = (Order) session.get(Order.class, 8);
order.getCustomer().setCustomerName("AAA"); //有对应的update的语句
}
2、双向1对多
Order类与上面的配置1样,Customer类修改以下
public class Customer {
private Integer customerId;
private String customerName;
/**
* 1.声明集合类型时,需使用接口类型。由于hibernate 在获得集合类型时,
* 返回的是Hibernate 内置的集合类型,而不是JavaSE 1个标准集合实现
* 2.需要把集合进行初始化,可以避免空指针异常
*/
private Set<Order> orders = new HashSet<Order>();
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
//省去get,set方法
}
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping⑶.0.dtd">
<hibernate-mapping package="com.changwen.hibernate4.mapped.oneToManyBoth.pojo">
<class name="Customer" table="customers">
<id name="customerId" column="customer_id" type="java.lang.Integer">
<generator class="native" />
</id>
<property name="customerName" column="customer_name" type="java.lang.String"/>
<!--
映照1对多的那个集合属性
name是Customer类里属性,table是Order.hbm.xml里的<class name="Order" table="orders">的table里的值
外键column跟Order.hbm.xml里 <many-to-one里的column里值1样\
inverse 属性的来决定是由双向关联的哪1方来保护表和表之间的关系
cascade 设置级联属性,开发时不建议设置该属性,建议使用手工的方式来处理
order-by 在查询时对集合的元素进行排序,order-by 中使用的是表的字段名,而不是类的属性名
-->
<set name="orders" table="orders" inverse="true" cascade="delete">
<key column="customer_ID2"/>
<one-to-many class="Order"/>
</set>
</class>
</hibernate-mapping>
把hbm.xml配置到cfg.xml里
/**
* 在hibernate.hbm.xml中通过对 inverse 属性的来决定是由双向关联的哪1方来保护表和表之间的关系.
* inverse = false 的为主动方,inverse = true 的为被动方, 由主动方负责保护关联关系
*
* 在没有设置 inverse=true 的情况下,父子两边都保护父子关系
*
* 在 1-n 关系中,将 n 方设为主控方将有助于性能改良!!
*/
@Test
public void testOneToManyBothSave(){
Customer customer1 = new Customer();
customer1.setCustomerName("AA");
Order order1 = new Order();
order1.setOrderName("ORDER⑴");
Order order2 = new Order();
order2.setOrderName("ORDER⑵");
//设定关联关系
order1.setCustomer(customer1);
order2.setCustomer(customer1);
customer1.getOrders().add(order1);
customer1.getOrders().add(order2);
/* 在没有设置inverse的情况下:先插入 Customer, 再插入 Order, 3 条 INSERT, 2 条update
由于1的那端和n的那端都保护关联关系,所有会多出update
如果在1的那端设置inverse=true,让1的那端放弃保护关系,则只有3条insert!!
建议设定set的invest=true,建议先插入1的那端,再插入多的那端
*/
session.save(customer1);
session.save(order1);
session.save(order2);
// 在没有设置inverse的情况下:先插入 Order, 再插入 Customer. 3 条 INSERT, 4 条 UPDATE
/* sessionPojo.save(order1);
sessionPojo.save(order2);
sessionPojo.save(customer1);*/
}
get,update,delete与上面类似
@Test
public void testUpdate(){
Customer customer = (Customer) session.get(Customer.class,1);
customer.getOrders().iterator().next().setOrderName("BBB");
}
@Test
public void testCascade() {
Customer customer = (Customer) session.get(Customer.class, 8);
customer.getOrders().clear();
}
生活不易,码农辛苦
如果您觉得本网站对您的学习有所帮助,可以手机扫描二维码进行捐赠