2月4日——培训第63天

    技术2022-05-11  64

     三元关系的另外两种处理方式:

    帮助手册中的chapter6中Advanced collectionMapping中的Ternary associations就是讲解三元关系处理的。

    1 使用Map,让关系成为其索引。(仅能单纯的映射三元关系)

    2 将一个关系重构为实体类,这是我们应用的最多的

    3 使用组成

    例1:

    配置文件:<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE hibernate-configuration PUBLIC          "-//Hibernate/Hibernate Configuration DTD 3.0//EN"          "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"><hibernate-configuration>  <session-factory>    <property name="dialect">org.hibernate.dialect.MySQLDialect</property>        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>    <property name="connection.url">jdbc:mysql:///struts</property>    <property name="connection.username">root</property>    <property name="connection.password">root</property>        <property name="show_sql">true</property>    <property name="format_sql">true</property>        <property name="current_session_context_class">thread</property>  </session-factory></hibernate-configuration>

     

    classroom、course和user三个表

    关系表classroom_tea_course:

    字段:tea_id:    INTEGERclass_id:  INTEGERcourse_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();}--------------------------------------------

    <?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"><hibernate-mapping package="cn.itcast.vo" auto-import="true">

     <class name="Teacher" table="teachers">  <id name="id" column="user_id">   <generator class="identity" />  </id>  <property name="empNo" column="emp_no" />  <property name="salary" column="salary" />

     </class>

     <class name="Course" table="courses">  <id name="id" column="course_id">   <generator class="identity" />  </id>  <property name="courseName" column="course_name" /> </class>

     <class name="Classroom" table="classrooms">  <id name="id" column="classroom_id">   <generator class="identity" />  </id>  <property name="location" />  <property name="maxSeat" column="max_seat" />  <map name="teacherCourses" table="classroom_tea_course">    <key column="class_id" />    //    <map-key-many-to-many class="Teacher" column="tea_id" />    <many-to-many class="Course" column="course_id"/>    //用classroom_tea_course的外键对Course的主键。  </map> </class>//键是老师,值是Course,教室号是外键</hibernate-mapping>

     

    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;----------------------------------------------------------------------------------------

     

    <map name="contracts"> <key column="employer_id" not-null="true"/> <map-key-many-to-many column="employee_id" class="Employee"/> <one-to-many class="Contract"/></map>以上应用在没有关系表的情况下,要求在Contract中必须有外键employer_id和employee_id,即one-to-many对应的表中有key和map-key-many-to-many所声明的外键

    <map name="connections"> <key column="incoming_node_id"/> <map-key-many-to-many column="outgoing_node_id" class="Node"/> <many-to-many column="connection_id" class="Connection"/></map>以上应用在有关系表的情况下,但map-key-many-to-many和many-to-many之间只能是多对一的关系。

    ====================================================================================================================================================下午课程开始:

    组成:

    组成代表了对象间不可分割的联系,成员与整体共存亡。使用组成可以提高代码的可重用性,降低维护难度,并且易于理解。例如:人和姓名之间就是组成关系,如果人不存在了其姓名也就没有存在的价值了。

    Person:id、name(Name)、age、gender、birthdayName:firstName、lastName

    Person中持有Name的实体,在数据表中把两个实体映射到一张表中去:person表:person_id first_name last_name age gender birthday

    映射文件:

    <class name="Person" table="person" >    <id name="id" column="person_id">       <generator class="identity" />    </id>    <property name="age"/>    <property name="gender"/>    <property name="birthday"/>    <component name="name" class="Name">      <parent name="owner" />//指明谁拥有name      <property name="firstName" column="first_name"/>      <property name="lastName" column="last_name"/>    </component>  </class>

    写两个类,一个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_dateline_items表:item_number、order_id、quantity、price

    映射文件:

    <class name="Order" table="orders" >    <id name="orderId" column="order_id">       <generator class="identity" />    </id>    <property name="name" column="order_name" />    <property name="date" column="order_date" />    <set name="items" table="line_items">       <key column="order_id" />       <composite-element class="Lineitem">         <property name="lineNum" column="item_number" />         <property name="quantity" />         <property name="price" />       </composite-element>    </set>  </class>

     

    动态组成以Map表示组成成员,key为属性名,value为属性值:<dynamic-component name="userAttributes">     <property name="foo" column="FOO" type="string"/>     <property name="bar" column="BAR" type="integer"/>     <many-to-one name="baz" class="Baz" column="BAZ_ID"/></dynamic-component>

    =============================================================

    映射三元关系的第三种方式:组成方式。

    其中第一种Map还有另外一种不使用关系表的方式,详见手册的6.3.4节。

    <map name="contracts"><key column="employer_id" not-null="true"/><map-key-many-to-many column="employee_id" class="Employee"/><one-to-many class="Contract"/></map>//没有关系表

    <map name="connections"><key column="incoming_node_id"/><map-key-many-to-many column="outgoing_node_id" class="Node"/><many-to-many column="connection_id" class="Connection"/></map>//有关系表

    -------------------------------------------------------手册的第8章节Component Mapping里面就是说的这种组合方式解决三元关系,也是对关系重构的一种方式。

    <class name="eg.Order" .... >....<set name="purchasedItems" table="purchase_items" lazy="true"><key column="order_id"><composite-element class="eg.OrderLine"><many-to-one name="purchaseDetails class="eg.Purchase"/><many-to-one name="item" class="eg.Item"/></composite-element></set></class>

    联合主键:8.4节:

    <composite-id name=“propertyName”       class="ClassName"       mapped=“true|false”        access="field|property|ClassName"> <key-property name="propertyName"         type="typename"         column="column_name"/> <key-many-to-one name="propertyName           class="ClassName“          column="column_name"/>......</composite-id>

    对于使用联合主键的POJO对象必须要重载equals方法和hashCode方法<composite-id><key-property name=“orderId"/><key-property name=“itemId"/></composite-id>

    注意事项:

    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接口

    弓燕军写的配置文件:

    <hibernate-configuration>  <session-factory>   <property name="dialect">org.hibernate.dialect.MySQLDialect</property>   <property name="connection.driver_class">com.mysql.jdbc.Driver</property>   <property name="connection.url">jdbc:mysql:///netstore?useUnicode=true&        characterEncoding=gbk</property>   <property name="connection.username">root</property>   <property name="connection.password">1234</property>      <property name="show_sql">true</property>   <property name="format_sql">true</property>   <property name="current_session_context_class">thread</property>   <mapping resource="org/hero/netstore/vo/Order.hbm.xml"/>   <mapping resource="org/hero/netstore/vo/LineItem.hbm.xml"/>  </session-factory></hibernate-configuration>---------------------------------------------------------------------------

    <hibernate-mapping auto-import="true" package="org.hero.netstore.vo"> <class name="Order" table="orders">  <id name="id" column="order_id" type="integer">   <generator class="native"/>  </id>  <property name="orderNumber" type="string">   <column name="ORDER_NUMBER"/>  </property>  <set name="lineItems">   <key column="order_id"/>   <one-to-many class="LineItem"/>  </set> </class>  <class name="LineItem" table="lineitems">  <composite-id name="key" class="CompositeKey">   <key-property name="item_id" column="item_id" type="integer"/>   <key-many-to-one name="order" class="Order" column="order_id"/>  </composite-id>  <property name="base_price" type="double"/>  <property name="quantity" type="integer"/>  </class></hibernate-mapping>------------------------------------------------------------------------------订单的实体类:

    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();

     }

    }


    最新回复(0)