Hibernate映射关联详解

来源:互联网 发布:淘宝上百度云盘被禁 编辑:程序博客网 时间:2024/05/23 11:54
  映射一对多关联关系
以Customer和Order为例:
一对多:
每个Customer可以有一个或者多个Order,因此Customer中应该有一个集合类型的属性,来引用所有关联的Order对象。
多对一:
Order到Customer的关联为多对一关联,每个Order对象都要有一个Customer对象。在Order中要有一个Customer类型的属性。
如果仅包含Customer到Order或者仅包含Order呆Customer的关联,就叫做单向关联。
同时包含两个关联的就坐双向关联。
第一部分:以Order和Customer为例,介绍如何映射多对一单向关联关系。
这个例子的特点是只在Order中加入Customer属性,建立单向关联。
1 数据库:
alter table ORDERS drop foreign key FK8B7256E516B4891C;
drop table if exists CUSTOMERS;
drop table if exists ORDERS;
create table CUSTOMERS (
   ID bigint not null,
   NAME varchar(15),
   primary key (ID)
);
create table ORDERS (
   ID bigint not null,
   ORDER_NUMBER varchar(15),
   CUSTOMER_ID bigint not null,
   primary key (ID)
);
alter table ORDERS add index FK8B7256E516B4891C (CUSTOMER_ID), add constraint FK8B7256E516B4891C foreign key (CUSTOMER_ID) references CUSTOMERS (ID);
2 类
Customers.java
package mypack;
 
import java.util.HashSet;
import java.util.Set;
 
/**
 *CustomersgeneratedbyMyEclipsePersistenceTools
 */
 
publicclass Customers implements java.io.Serializable {
 
    // Fields
 
    private Long id;
 
    private String name;
 
    // Constructors
 
    /**defaultconstructor*/
    public Customers() {
    }
 
    /**fullconstructor*/
    public Customers(String name) {
       this.name = name;
    }
 
    // Property accessors
 
    public Long getId() {
       returnthis.id;
    }
 
    publicvoid setId(Long id) {
        this.id = id;
    }
 
    public String getName() {
       returnthis.name;
    }
 
    publicvoid setName(String name) {
       this.name = name;
    }
 
}
 
Orders.java
package mypack;
 
/**
 *OrdersgeneratedbyMyEclipsePersistenceTools
 */
 
publicclass Orders implements java.io.Serializable {
 
    // Fields
 
    private Long id;
 
    private Customers customers;
 
    private String orderNumber;
 
    // Constructors
 
    /**defaultconstructor*/
    public Orders() {
    }
 
    /**minimalconstructor*/
    public Orders(Customers customers) {
       this.customers = customers;
    }
 
    /**fullconstructor*/
    public Orders(Customers customers, String orderNumber) {
       this.customers = customers;
       this.orderNumber = orderNumber;
    }
 
    // Property accessors
 
    public Long getId() {
       returnthis.id;
    }
 
    publicvoid setId(Long id) {
       this.id = id;
    }
 
    public Customers getCustomers() {
       returnthis.customers;
    }
 
    publicvoid setCustomers(Customers customers) {
       this.customers = customers;
    }
 
    public String getOrderNumber() {
       returnthis.orderNumber;
    }
 
    publicvoid setOrderNumber(String orderNumber) {
       this.orderNumber = orderNumber;
    }
 
}
 
测试类:
BusinessService.java
package mypack;
 
import java.util.Iterator;
import java.util.List;
 
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
 
import com.sun.org.apache.xpath.internal.operations.Or;
 
import sessionFactory.HibernateSessionFactory;
 
publicclass BusinessService {
 
    public List findOrdersByCustomer(Customers customer) throws Exception {
 
       Session session = null;
       Transaction tr = null;
       try {
           session = HibernateSessionFactory.getSession();
           tr = session.beginTransaction();
 
           Query query = session
                  .createQuery("from Orders as o where o.customers.id="
                         + customer.getId());
           List orders = query.list();
           tr.commit();
 
           return orders;
       } catch (Exception e) {
           // TODO: handle exception
           if (tr != null) {
              tr.rollback();
           }
           throw e;
       } finally {
           session.close();
       }
    }
 
    public Customers findCustomer(Long customer_id) throws Exception {
       Session session = null;
       Transaction tr = null;
       try {
 
           session = HibernateSessionFactory.getSession();
           tr = session.beginTransaction();
           Customers customer = (Customers) session.load(Customers.class,
                  customer_id);
           tr.commit();
           return customer;
       } catch (Exception e) {
           // TODO: handle exception
           if (tr != null) {
              tr.rollback();
           }
           throw e;
       } finally {
           session.close();
       }
    }
 
    publicvoid saveCustomerAndOrder() throws Exception {
       Session session = null;
       Transaction tr = null;
       try {
           session = HibernateSessionFactory.getSession();
           tr = session.beginTransaction();
 
           Customers customer = new Customers("zhang");
           session.save(customer);
 
           Orders order1 = new Orders(customer, "order1");
           Orders order2 = new Orders(customer, "order2");
           session.save(order1);
           session.save(order2);
           tr.commit();
       } catch (Exception e) {
           // TODO: handle exception
           if (tr != null) {
              tr.rollback();
           }
           throw e;
       } finally {
           session.close();
       }
    }
 
    publicvoid saveCustomerAndOrdeWithCascader() throws Exception {
       Session session = null;
       Transaction tr = null;
       try {
           session = HibernateSessionFactory.getSession();
           tr = session.beginTransaction();
 
           Customers customer = new Customers("zhang");
           // session.save(customer);//映射文件中加入cascade="save-update"
 
           Orders order1 = new Orders(customer, "order1");
           Orders order2 = new Orders(customer, "order2");
           session.save(order1);
           session.save(order2);
           tr.commit();
       } catch (Exception e) {
           // TODO: handle exception
           if (tr != null) {
              tr.rollback();
           }
           throw e;
       } finally {
           session.close();
       }
    }
 
    publicvoid printOrders(List orders) {
       for (Iterator it = orders.iterator(); it.hasNext();) {
           Orders order = (Orders) it.next();
           System.out.println("OrderNumber of "
                  + order.getCustomers().getName() + " :"
                  + order.getOrderNumber());
       }
    }
 
    publicvoid test() throws Exception {
       saveCustomerAndOrder();
       saveCustomerAndOrdeWithCascader();
       Customers customer = findCustomer(new Long(1));
       List orders = findOrdersByCustomer(customer);
       printOrders(orders);
    }
 
    /**
     *@paramargs
     *@throwsException
     */
    publicstaticvoid main(String[] args) throws Exception {
       // TODO Auto-generated method stub
 
       BusinessService b = new BusinessService();
       b.test();
    }
 
}
3 映射文件:
Customers.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
    Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
    <class name="mypack.Customers" table="customers"
       catalog="onetomany" lazy="false">
       <id name="id" type="java.lang.Long">
           <column name="ID" />
           <generator class="increment" />
       </id>
       <property name="name" type="java.lang.String">
           <column name="NAME" length="15" />
       </property>
    </class>
</hibernate-mapping>
Orders.hbm.xml
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
    Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
    <class name="mypack.Orders" table="orders" catalog="onetomany">
       <id name="id" type="java.lang.Long">
           <column name="ID" />
           <generator class="increment" />
       </id>
       <many-to-one name="customers" class="mypack.Customers"
           fetch="select" cascade="save-update">
           <column name="CUSTOMER_ID" not-null="true" />
       </many-to-one>
       <property name="orderNumber" type="java.lang.String">
           <column name="ORDER_NUMBER" length="15" />
       </property>
    </class>
</hibernate-mapping>
 
小结:本例子的重点是级联保存和更新的使用。当建立了Order到Customer的单向关联时,把映射文件中的<many-to-one>的cascade属性设置为save-update,只做保存Order的操作,与Order对应的customer对象就自动被保存了。(前提是在测试的文件中加入了对Order的Customer属性的设置)




映射一对多双向关联关系
1   Customers 类中加如set类型的 Orders属性,Orders类中加入Customer类型的customer属性。
2    测试时,建立两者一对多的双向关联关系。
     Customers customer=new Customer(“Tom”,new HashSet());
Order order=new Order();
 
建立Customer对象和Orders对象的双向关联关系。
 
order.setCustomer(customer);
customer.getOrders().add(order);
     
 只要将 Set的cascade属性设置为save-update,就可以直接保存customer,与之关联的order对象就会自动被持久化。
     Session.save(customer);
3 set的inverse属性。
   当建立了对象的双向关联关系时,Hibernate会根据:
order.setCustomer(customer);
customer.getOrders().add(order);
     对数据库做两侧更新,其实这里是重复执行了SQL语句,势必会影响到程序的反应速度和性能。
         只要将设置set inverse=”true”,
     <set name="orderses" inverse="true" cascade="save-update">
            <key>
                <column name="CUSTOMER_ID" not-null="true" />
            </key>
            <one-to-many class="mypack.Orders" />
        </set>
这段代码表示:在Customer和Order的双向关联关系时中,Customer的关联只是Order关联的镜像.当Hibernate测到持久化对象Customer和Order对象的状态都发生变化时,仅仅按照Order对象的状态变化同步更新数据库。
小结:1 在映射一对多的双向关联关系时,应该在one方把 inverse属性设成true,这样可以提高应用的性能。
      2 在建立两个对象的双向关联时,应该同时修改关联两端的对象的相应属性:
                          order.setCustomer(customer);
customer.getOrders().add(order);
        这样才会使程序更加健壮,提高业务逻辑的独立性。
Cascade的delete属性:如果希望在删除Customer对象时同时删除与之关联的Order对象。
Cascade的all-delete-orphan属性:
  1 保存或更新Customer对象时,级联保存更新所有关联的Order对象。相当于:save-update
 2 当删除Customer对象时,级联删除所有关联的Order对象。相当于:delete
 3 删除不在和Customer对象关联的多有Order对象
 
 总结:One   To   Many 双相关联
 Java类中: One加入 Set类型的 Many属性,Many加入One类型的属性。
业务程序中:为了使程序更加健壮,建立One到Many,和Many到one的双向关联。
影射文件中:将One中的set 的inverse属性设成true(默认是false),这样Hibernate不会因为我们在业务逻辑中做的双向关联而产生重复的更新数据库的操作,也提高了效率。
 
                     适当选择cascade的值:save-update ,delete , all-delete-orphan



自身一对多双向关联关系
1 数据库:
altertable CATEGORIES dropforeignkey FK6A31321CDBFCB7FC;
droptableifexists CATEGORIES;
createtable CATEGORIES (
   ID bigintnotnull,
   NAMEvarchar(15),
   CATEGORY_ID bigint,
   primarykey (ID)
);
altertable CATEGORIES addindex FK6A31321CDBFCB7FC (CATEGORY_ID), addconstraint FK6A31321CDBFCB7FC foreignkey (CATEGORY_ID) references CATEGORIES (ID);
三个字段: id name category_id(外键,参照本表的id主键)
2 类文件
package mypack;
 
import java.util.HashSet;
import java.util.Set;
 
/**
 *CategoriesgeneratedbyMyEclipsePersistenceTools
 */
 
publicclass Categories implements java.io.Serializable {
 
    // Fields
 
    private Long id;
 
    private Categories parentCategory;
 
    private String name;
 
    private Set childCategorieses = new HashSet(0);
 
    // Constructors
 
    /**defaultconstructor*/
    public Categories() {
    }
 
    public Categories(String name, Categories parentCategory,
           Set childCategorieses) {
 
       this.name = name;
       this.parentCategory = parentCategory;
       this.childCategorieses = childCategorieses;
    }
 
    /**fullconstructor*/
 
    // Property accessors
    public Long getId() {
       returnthis.id;
    }
 
    publicvoid setId(Long id) {
       this.id = id;
    }
 
    public String getName() {
       returnthis.name;
    }
 
    publicvoid setName(String name) {
       this.name = name;
    }
 
    public Set getChildCategorieses() {
       returnchildCategorieses;
    }
 
    publicvoid setChildCategorieses(Set childCategorieses) {
       this.childCategorieses = childCategorieses;
    }
 
    public Categories getParentCategory() {
       returnparentCategory;
    }
 
    publicvoid setParentCategory(Categories parentCategory) {
       this.parentCategory = parentCategory;
    }
 
}
分析:
private Categories parentCategory;
指向某个分类的父类,父类只能是一个Category类型的对象。
    private Set childCategorieses = new HashSet(0);
指向某个分类的子类:子类可以是一个或者多个的Category类型对象。
3映射文件
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!--
    Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping>
    <class name="mypack.Categories" table="categories"
       catalog="onetomany">
       <id name="id" type="java.lang.Long">
           <column name="ID" />
           <generator class="increment" />
       </id>
       <many-to-one name="parentCategory" class="mypack.Categories"
           fetch="select" cascade="save-update">
           <column name="CATEGORY_ID" />
       </many-to-one>
       <property name="name" type="java.lang.String">
           <column name="NAME" length="15" />
       </property>
       <set name="childCategorieses" inverse="true" lazy="false"
           cascade="save-update">
           <key>
              <column name="CATEGORY_ID" />
           </key>
           <one-to-many class="mypack.Categories" />
       </set>
    </class>
</hibernate-mapping>
 
注意红色部分的parentCategory childCategorieses 属性的映射方法。他们都依赖外键 <column name="CATEGORY_ID" />
4 测试类
package mypack;
 
import java.util.HashSet;
 
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.Transaction;
 
import sessionFactory.HibernateSessionFactory;
 
publicclass BusinessService {
 
    publicvoid saveCategoryWithCascade() throws Exception {
 
       Session session = null;
       Transaction tr = null;
       try {
           session = HibernateSessionFactory.getSession();
           tr = session.beginTransaction();
           Categories foodCategory = new Categories("food", null,
                  new HashSet());
           Categories fruitCategory = new Categories("fruit", null,
                  new HashSet());
           Categories vegetableCategory = new Categories("vegetable", null,
                  new HashSet());
           Categories appleCategory = new Categories("apple", null,
                  new HashSet());
           Categories orangeCategory = new Categories("orange", null,
                  new HashSet());
           Categories tomatoCategory = new Categories("tomato", null,
                  new HashSet());
 
           /*
            * 建立食品类别和水果类别之间的关联关系
            */
           foodCategory.getChildCategorieses().add(fruitCategory);
           fruitCategory.setParentCategory(foodCategory);
 
           /*
            * 建立食品类别和蔬菜类别之间的关联关系
            */
           foodCategory.getChildCategorieses().add(vegetableCategory);
           vegetableCategory.setParentCategory(foodCategory);
 
           /*
            * 建立水果类别和苹果之间的关联关系
            */
 
           fruitCategory.getChildCategorieses().add(appleCategory);
           appleCategory.setParentCategory(fruitCategory);
 
           /*
            * 建立水果类别和橘子之间的关联关系
            */
 
           fruitCategory.getChildCategorieses().add(orangeCategory);
           orangeCategory.setParentCategory(fruitCategory);
 
           /*
            * 建立水果类别和番茄之间的关联关系
            */
 
           fruitCategory.getChildCategorieses().add(tomatoCategory);
           tomatoCategory.setParentCategory(fruitCategory);
 
           session.save(foodCategory);
           tr.commit();
 
       } catch (Exception e) {
           // TODO: handle exception
           if (tr != null) {
              tr.rollback();
           }
           throw e;
       } finally {
           session.close();
       }
    }
 
    publicvoid modifyCategoryAssociation() throws Exception {
 
       Session session = null;
       Transaction tr = null;
       try {
           session = HibernateSessionFactory.getSession();
           tr = session.beginTransaction();
 
           Categories fruitCategory = findCategoryByName(session, "fruit");
           Categories tomatoCategory = findCategoryByName(session, "tomato");
           Categories vegetableCategory = findCategoryByName(session,
                  "vegetable");
           /*
            * 建立蔬菜类别和西红柿之间的关联关系
            */
           vegetableCategory.getChildCategorieses().add(tomatoCategory);
           tomatoCategory.setParentCategory(vegetableCategory);
 
           /*
            * 解除西红柿和水果之间的关系
            */
 
           fruitCategory.getChildCategorieses().remove(tomatoCategory);
           tr.commit();
       } catch (Exception e) {
           // TODO: handle exception
           if (tr != null) {
              tr.rollback();
           }
           throw e;
       } finally {
           session.close();
       }
    }
 
    public Categories findCategoryByName(Session session, String name)
           throws Exception {
 
       Query query = session
              .createQuery("from Categories as c where c.name=?");
       query.setString(0, name);
       Categories category = (Categories) query.uniqueResult();
 
       return category;
 
    }
 
    publicvoid test() throws Exception {
       saveCategoryWithCascade();
       modifyCategoryAssociation();
    }
 
    /**
     *@paramargs
     *@throwsException
     */
    publicstaticvoid main(String[] args) throws Exception {
       // TODO Auto-generated method stub
 
       new BusinessService().test();
    }
}