双向多对一
双向 1-n 与 双向 n-1 是完全相同的两种情形
双向 1-n 需要在 1 的一端可以访问 n 的一端, 反之依然.
域模型:从 Order 到 Customer 的多对一双向关联需要在Order 类中定义一个 Customer 属性, 而在 Customer 类中需定义存放 Order 对象的集合属性
customer类
public class Customer {
private int customerId;
private String customerName;
private Set<Order> orders=new HashSet<>();
//在定义集合属性时, 通常把它初始化为集合实现类的一个实例. 这样可以提高程序的健壮性, 避免应用程序访问取值为 null 的集合的方法抛出 NullPointerException
public Set<Order> getOrders() {
return orders;
}
public void setOrders(Set<Order> orders) {
this.orders = orders;
}
public int getCustomerId() {
return customerId;
}
public void setCustomerId(int customerId) {
this.customerId = customerId;
}
public String getCustomerName() {
return customerName;
}
public void setCustomerName(String customerName) {
this.customerName = customerName;
}
}
order类
public class Order {
private int orderId;
private String orderName;
private Customer customer;
public int getOrderId() {
return orderId;
}
public void setOrderId(int 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;
}
}
Customer.hbm.xml
<hibernate-mapping package="com.eduask.chp.beans">
<class name="Customer" table="CUSTOMER">
<id name="customerId" type="int">
<column name="CUSTOMER_ID" />
<generator class="native" />
</id>
<property name="customerName" type="java.lang.String">
<column name="CUSTOMER_NAME" />
</property>
<!-- 映射一对多 的结合属性 -->
<set name="orders" table="ORDERS">
<key column="ORDER_ID"></key>
<one-to-many class="Order"/>
</set>
</class>
</hibernate-mapping>
Order.hbm.xml
<hibernate-mapping package="com.eduask.chp.beans" >
<class name="Order" table="ORDERS">
<id name="orderId" type="int">
<column name="ORDER_ID" />
<generator class="native" />
</id>
<property name="orderName" type="java.lang.String">
<column name="ORDER_NAME" />
</property>
<!-- 多对一映射 -->
<!--name:一的一方的名称
class:一的一方的类
column:多的一方的外键
-->
<many-to-one name="customer" class="Customer" column="CUSTOMER_ID">
</many-to-one>
</class>
</hibernate-mapping>
@Test
public void testSave() {
Customer customer=new Customer();
Order order=new Order();
customer.setCustomerName("张三");
order.setOrderName("沐浴露");
order.setCustomer(customer);
customer.getOrders().add(order);
session.save(customer);
session.save(order);
看结果你会发现会两条insert语句 ,一句update语句
单向前一篇我们已经知道了只有两条insert语句
原因:一的一方与n方都要维护关联关系,之前的单向只有一方维护
那么如何设定他们的关联关系呢?
在hibernate中通过对 inverse 属性的来决定是由双向关联的哪一方来维护表和表之间的关系. inverse = false 的为主动方,inverse = true 的为被动方, 由主动方负责维护关联关系
在没有设置 inverse=true 的情况下,父子两边都维护父子
关系
在 1-n 关系中,将 n 方设为主控方将有助于性能改善(如果要国家元首记住全国人民的名字,不是太可能,但要让全国人民知道国家元首,就容易的多)
<set name="orders" table="ORDERS" inverse="true">
增加前面已经示例了
查:
@Test
public void testGet() {
Customer customer=(Customer) session.get(Customer.class, 1);
System.out.println(customer.getCustomerName());
System.out.println(customer.getOrders().getClass().getName());
//session.close();
//System.out.println(customer.getOrders().isEmpty());
}
org.hibernate.collection.internal.PersistentSet
返回多的一端的集合是Hibernate的内置的集合类型,该类型具有延迟加载和存放代理对象的功能
所以这里要注意懒加载问题,当session关闭的时候,想获得多的一方的信息的时候会报懒加载异常
改:
@Test
public void testUpdate() {
Customer customer=(Customer) session.get(Customer.class, 1);
customer.setCustomerName("张学友");
customer.getOrders().iterator().next().setOrderName("羽绒服");
}
删:
下面代码是不可行的,涉及到级联
@Test
public void testDelete() {
Customer customer=(Customer) session.get(Customer.class, 1);
customer.setCustomerId(1);
session.delete(customer);
}
为什么不行?
因为对象之间有关联,这个时候你就要需要设置级联.
在对象 – 关系映射文件中, 用于映射持久化类之间关联关系的元素, <set>, <many-to-one> 和 <one-to-one> 都有一个 cascade 属性, 它用于指定如何操纵与当前对象关联的其他对象.
<set name="orders" table="ORDERS" inverse="true" cascade="delete">
排序
<set> 元素有一个 order-by 属性, 如果设置了该属性, 当 Hibernate 通过 select 语句到数据库中检索集合对象时, 利用 order by 子句进行排序.order-by 后面跟着的是数据库表的字段名
<set name="orders" table="ORDERS" inverse="true" cascade="delete" order-by="ORDER_ID DESC">