三元关系的另外两种处理方式:
帮助手册中的chapter6中Advanced collectionMapping中的Ternary associations
就是讲解三元关系处理的。
1 使用Map,让关系成为其索引。(仅能单纯的映射三元关系)
2 将一个关系重构为实体类,这是我们应用的最多的
3 使用组成
例1:
配置文件:
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
classroom、course和user三个表
关系表classroom_tea_course:
字段:
tea_id: INTEGER
class_id: INTEGER
course_id: INTEGER
以上三个每一个都是外键,都对应着一个表
package cn.itcast.vo;
import java.util.HashSet;
import java.util.Set;
public class Teacher {
private int id;
private String empNo;
private Float salary;
}
----------------------------------------
package cn.itcast.vo;
public class Course {
private int id;
private String courseName;
public boolean equals(Object obj) {
// TODO Auto-generated method stub
if(obj==null) return false;
if(obj==this) return true;
if(obj instanceof Course) {
Course c = (Course) obj;
if(c.getId()==id) return true;
}
return false;
}
public int hashCode() {
// TODO Auto-generated method stub
return id;
}
}
------------------------------------------
package cn.itcast.vo;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class Classroom {
private int id;
private String location;
private int maxSeat;
private Map teacherCourses = new HashMap();
}
--------------------------------------------
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
//键是老师,值是Course,教室号是外键
public class Demo
{
public static void main(String[] args)
{
SessionFactory factory = new Configuration()
.addResource("cn/itcast/vo/User.hbm.xml")
.configure()
.buildSessionFactory() ;
//由于工程里面的实体类中没有User,所以这里必须用addResource!
Session session = factory.getCurrentSession() ;
session.beginTransaction() ;
Teacher t = (Teacher)session.get(Teacher.class,new Integer(1));
Course c = (Course)session.get(Course.class,new Integer(1));
Classroom cr = (Classroom)session.get(Classroom.class,new Integer(1));
cr.getTeacherCourses().put(t,c);
//三个实体都是通过get方法加载进来的,所以都处于持久状态……
cr.getTeacherCourses().put(t,new Course().setId(2));
//由于是map,所以上面这句话将会覆盖上面的c……其实说白了teacher和classroom由于
//在map里面是键值对的关系,所以teacher和classroom必须是一对一或是多对一的关系,这就对
//多元关系造成了一定的局限……………………所以这种方法几乎不太用。(key和value必须是一对一或是多对一
//但是绝对不可以是一对多,否则绝对会出现覆盖现象)
session.getTransaction().commit() ;
session.close() ;
factory.close() ;
}
}
三者之间的关系:Teacher和Course:一对一或多对一,Teacher对的Course永远只有一个。但是也可以让
一个老师对应多门课程,通过重载equals方法的方式、让key以某种方式和上一个不一样就可以了。
教室和老师课程的实体map之间是多对多关系。
其实由于一门课程只能在一个教室里面上,一个教室可以上多门课程,所以最好应该让Classroom和Course之间
组成map,而且要让课程为key,教室为value;
----------------------------------------------------------------------------------------
以上应用在没有关系表的情况下,
要求在Contract中必须有外键employer_id和employee_id,
即one-to-many对应的表中有key和map-key-many-to-many所声明的外键
以上应用在有关系表的情况下,
但map-key-many-to-many和many-to-many之间只能是多对一的关系。
==========================================================================
==========================================================================
下午课程开始:
组成:
组成代表了对象间不可分割的联系,成员与整体共存亡。
使用组成可以提高代码的可重用性,降低维护难度,并且易于理解。
例如:人和姓名之间就是组成关系,如果人不存在了其姓名也就没有存在的价值了。
Person:id、name(Name)、age、gender、birthday
Name:firstName、lastName
Person中持有Name的实体,在数据表中把两个实体映射到一张表中去:
person表:person_id first_name last_name age gender birthday
映射文件:
写两个类,一个Person,一个Name,然后Name中持有一个owner,指明谁
拥有这个名字。
Name name = new Name();
name.setFirstName("bill");
name.setLastName("gates");
Person p = new Person();
p.setName(name);
session.save(p);
有些时候组成整体的部分并非仅有一个,如一栋楼由多个单元组成,一个单
元由多个房间组成,一个房间又由多个室组成。
在组成成为集合时,必须由独立的表存储组成的成员,然后通过主外键关系
组成成员。需要指明组成外键。
在使用上与一对多的关系相差无几。
----------------------------------------------------------
再来考虑订单和订单项之间的关系
订单Orders有属性id、name、date和items
订单项Lineitem中有属性lineNumber、order、quantity、price
Orders和Lineitem之间是一对多的关系。
orders表:order_id、order_name、order_date
line_items表:item_number、order_id、quantity、price
映射文件:
动态组成以Map表示组成成员,key为属性名,value为属性值:
=============================================================
映射三元关系的第三种方式:组成方式。
其中第一种Map还有另外一种不使用关系表的方式,详见手册的6.3.4节。
//没有关系表
//有关系表
-------------------------------------------------------
手册的第8章节Component Mapping里面就是说的这种组合方式解决三元关系,
也是对关系重构的一种方式。
....
联合主键:8.4节:
mapped=“true|false”
access="field|property|ClassName">
column="column_name"/>
......
对于使用联合主键的POJO对象必须要重载equals方法和hashCode方法
注意事项:
You may use a component as an identifier of an entity class. Your component
class must satisfy certain requirements:
It must implement java.io.Serializable.
It must re-implement equals() and hashCode(), consistently with the database's
notion of composite key equality.
类必须实现Serializable接口并且要重载equals和hashCode方法,但是对于Hibernate3来说,
第二个要求并不是必须的,但是你最好还是重载它。
-------------------------------------------------------------------------------
下面拿订单和订单项来举例,联合主键是订单号和订单项的号联合起来作为主键。
先不做成组成的关系,让订单和订单项先映射成各自独立的实体。
Order里面持有一个Set,Set里面都是订单项,然后LineItem中持有一个Order实体对象。
写一个类继承自Serializable接口
弓燕军写的配置文件:
characterEncoding=gbk
---------------------------------------------------------------------------
------------------------------------------------------------------------------
订单的实体类:
public class Order implements Serializable{
/**
*
*/
private static final long serialVersionUID = 0;
private int id;
private String orderNumber;
private int item_id;
private Set lineItems = new HashSet();
public boolean equals(Object obj) {
if(obj == null)
return false;
if(obj == this)
return true;
if(obj instanceof Order)
{
Order o = (Order)obj;
if(o.getId() == id)
{
return true;
}
}
return false;
}
public int hashCode() {
return id;
}
}
订单项:
public class LineItem {
private CompositeKey key;
private double base_price;
private int quantity;
}
联合主键也需要一个类:
public class CompositeKey implements Serializable{
private static final long serialVersionUID = 0;
private Order order;
private int item_id;
public int getItem_id() {
return item_id;
}
public void setItem_id(int item_id) {
this.item_id = item_id;
}
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
@Override
public boolean equals(Object obj) {
if(obj == null)
return false;
if(obj == this)
return true;
if(!(obj instanceof CompositeKey))
return false;
CompositeKey c = (CompositeKey)obj;
if(!c.getOrder().equals(order))
return false;
if(c.getItem_id() != item_id)
return false;
return true;
}
@Override
public int hashCode() {
return order.getId() + item_id;
}
}
-----------------------------------------
测试类:
public class Demo {
/**
* @param args
*/
public static void main(String[] args) {
SessionFactory factory = new Configuration().configure().buildSessionFactory();
Session session = null;
try {
session = factory.getCurrentSession();
session.beginTransaction();
Order order = new Order();
order.setOrderNumber("111111");
session.save(order);
CompositeKey key = new CompositeKey();
key.setOrder(order);
LineItem item1 = new LineItem();
item1.setKey(key);
item1.setBase_price(20.5);
item1.setQuantity(5);
LineItem item2 = new LineItem();
item2.setKey(key);
item2.setBase_price(80.9);
item2.setQuantity(10);
session.save(item1);
session.save(item2);
session.getTransaction().commit();
} catch (HibernateException e) {
if(session != null && session.getTransaction() != null)
{
session.getTransaction().rollback();
}
e.printStackTrace();
}finally{
if(session != null)
{
session.close();
session = null;
}
}
factory.close();
}
}