Hibernate第三节(复合主键+映射问题(集合映射、一对一、一对多、多对多映射))

本文详细介绍了Hibernate框架中各种关联关系的映射方法,包括复合主键、集合映射、一对一、一对多及多对多关系的具体实现方式,并提供了丰富的代码实例。

1>:复合主键

        什么是复合主键?

        就是当一个表里面的一个字段不能唯一的标识一行数据的话那么这个时候就需要这个表的多个字段来共同作为主键、这样的主键就叫做复合主键

       Hibernate中的复合主键的使用(下面以用户为例、假设用户表中没有主键id、要使用uName和uAddress来共同作为主键)

     1>:将要作为复合主键的这些属性抽取城一个复合主键的类     
public class CompositeKey implements Serializable{
	private String uName;
	private String uAddress;

        setter...
        getter...
}
     2>:在用户实体中引用这个类
public class User implements Serializable{	
	private Date uBirth;
	private Gender gender;
	private String uPwd;
	//在这个类里面保存复合主键的引用
	private CompositeKey key;      //我们的主键
       setter...
       getter...

}
   3>:在配置文件中做如下配置(User.hbm.xml)
<hibernate-mapping package="com.qf.compositekey">
   <class name="User" table="t_user">
       
       <!--下面就配置我们的复合主键-->
       <composite-id name="key" class="com.qf.compositekey.CompositeKey">
         <key-property name="uName" column="u_name"></key-property>
         <key-property name="uAddress" column="u_address"></key-property>
       </composite-id>
       
       <!--下面就应该配置我们的普通字段-->
       <property name="gender" column="u_gender" length="5"></property>
       <property name="uBirth" column="u_birth"></property>
       <property name="uPwd" column="u_pwd"></property>
   </class>
</hibernate-mapping>
 4>:测试我们的复合主键
@Test
	public void testAdd() throws Exception {
		Session session=getSession();
		CompositeKey key=new CompositeKey();
		key.setuAddress("四川成都");
		key.setuName("小波波");
		//准备我们的保存数据对象
		User user=new User(new Date(1234566),Gender.man,"123", key);
		session.save(user);
		close();
	}

2>:集合映射

      需求:当我们在购买商品的时候、有可能用户处于不同的地点、所以需要填写不同的地址,所以假设一个用户可以对应多个地址(那么这种情况下  用户---->地址之间的关系是一对多)

   使用Set集合映射实现如下:   
    1>:定义用户实体  
public class User implements Serializable{
	private int uId;
	private String uName;
	private String uNickName;
	private String uTelNum;
	//一个用户对应了多个地址  用户和地址之间是 一对多
	private Set<String> address=new HashSet<String>();
      setter...
      getter...
}
    2>:配置的映射文件如下
<hibernate-mapping package="com.qf.collection">
   
   <class name="User" table="t_user">
   
      <!--配置的是主键-->
      <id name="uId">
        <generator class="native"></generator>
      </id>
      
      <!--配置的是普通字段-->
      <property name="uName" length="10"></property>
      <property name="uNickName" length="10"></property>
      <property name="uTelNum" length="11"></property>
      
      <!--配置我们的集合映射了-->
     <set name="address" table="t_address">
         这里需要使用上面这个class的id来作为外键
                                 下面这个key表示的是要对应上面的class中的主键  
             column:表示的是上面的主键对应t_address这个表的外键的名字(随便写都是对的  只不过还是要见名之意
         <key column="u_id"></key>
         下面就配置地址的这个列了  在集合中配置普通字段都是element
         <element column="address" type="java.lang.String" length="10"></element>
      </set> 
  </class>
</hibernate-mapping>
}
   3>:测试代码如下
@Test
	public void testSet() throws Exception {
		Session session=getSession();	
		Set<String> address=new HashSet<String>();
		address.add("中国云南");
		address.add("中国海南");
		address.add("中国甘肃");
		address.add("中国河南");
		User user=new User(1,"铁蛋","秋红叶落","120",address);
		//执行业务逻辑
		session.save(user);
		close();
	}

  使用List实现如下

    1>:编写用户实体
public class User implements Serializable{
	private int uId;
	private String uName;
	private String uNickName;
	private String uTelNum;
	//一个用户对应了多个地址  用户和地址之间是 一对多
        private List<String> address=new ArrayList<String>();
  setter...
  getter...
}

  2>:映射文件如下
<hibernate-mapping package="com.qf.collection">
   
   <class name="User" table="t_user">

      <!--配置的是主键-->
      <id name="uId">
        <generator class="native"></generator>
      </id>
      
      <!--配置的是普通字段-->
      <property name="uName" length="10"></property>
      <property name="uNickName" length="10"></property>
      <property name="uTelNum" length="11"></property>
      
      <!--配置我们的集合映射了-->
      <list name="address" table="t_address">
        <key column="u_id"></key>
        List集合和Set集合的区别就是List集合要多一个排序的列
            这个列的名字你是可以随便写的 这个是用来排序用的
        <list-index column="index1"></list-index>
        <element column="address" type="java.lang.String" length="10"></element>
      </list> 
   </class>
</hibernate-mapping>
   3>:测试类
	@Test
	public void testList() throws Exception {
		
		Session session=getSession();
		List<String> address=new ArrayList<String>();
		address.add("中国云南");
		address.add("中国海南");
		address.add("中国甘肃");
		address.add("中国河南");
		User user=new User(1,"铁蛋","秋红叶落","120",address);
		session.save(user);
		
		close();
	}

   Map集合的实现如下

    1>:编写用户的实体类
public class User implements Serializable{
	private int uId;
	private String uName;
	private String uNickName;
	private String uTelNum;
	private Map<String,String> address=new HashMap<String,String>();
 }
     2>:映射文件如下
<hibernate-mapping package="com.qf.collection">
   
   <class name="User" table="t_user">
   
      <!--配置的是主键-->
      <id name="uId">
        <generator class="native"></generator>
      </id>
      
      <!--配置的是普通字段-->
      <property name="uName" length="10"></property>
      <property name="uNickName" length="10"></property>
      <property name="uTelNum" length="11"></property>
      
      <!--配置我们的集合映射了-->      
      <!--下面玩下Map集合-->
      <map name="address" table="t_address">
         <!--配置的是外键-->
         <key column="u_id"></key>
         <map-key type="java.lang.String" column="addKey" length="10"></map-key>
          <!--配置的值-->
         <element column="address" type="java.lang.String" length="10"></element> 
      </map>     
   </class>
</hibernate-mapping>
   3>:测试文件的使用
@Test
	public void testMap() throws Exception {
		
		Session session=getSession();
		Map<String,String> address=new HashMap<String, String>();
		address.put("第一个地址","海南三亚");
		address.put("第二个地址","海南海口");
		address.put("第三个地址","海南文昌");
		address.put("第四个地址","四川成都");
		User user=new User(1,"铁蛋","秋红叶落","120",address);
		session.save(user);
		
		close();
	}


3>:一对一映射

    基于外键来进行映射(在身份证中维护用户的id作为外键)

     需求:用户和身份证的关系使用Hibernate映射文件来描述出来

               一个用户只有一个身份证       一个身份证只是对应了一个用户

              用户和身份证之间的关系:一对一

    1>:设计用户的实体类
public class User {
	private int uId;   
	private String uName;   
	private String uAddress;
	private IdCard idCard;
     
        setter...
       getter...
 }
  2>:设置身份证这个实体类
public class IdCard {
	private String cardNum;    //身份证号码
	private Date cardTime;     //身份证的有效时间
	private User user;         //一个身份证对应了一个用户
       setter...
      getter...
}
  3>:用户的配置文件
<!--这里的package用来指定实体所在的包
         这里的这个package是用来存放我们的实体类所在的包的
         如果这里省略的话那么就需要在class的name上面编写全路径
-->
<hibernate-mapping package="com.qf.one2one">
   
   <class name="User">
     <!--配置主键-->
     <id name="uId">
       <generator class="native"></generator>
     </id>
     <!--配置其他的字段-->
     <property name="uAddress"></property>
     <property name="uName"></property>
     
      <!--配置一对一的映射的时候分为 有外键的一方和没有外键的一方-->
      <!--没有外键的这一方-->
      <one-to-one name="idCard" class="com.qf.one2one.IdCard" cascade="all"></one-to-one>
   </class>
</hibernate-mapping>
4>:有外键的一方IdCard的配置
<!--这里的package用来指定实体所在的包
         这里的这个package是用来存放我们的实体类所在的包的
         如果这里省略的话那么就需要在class的name上面编写全路径
-->
<hibernate-mapping package="com.qf.one2one">
   
   <class name="IdCard">
     <!--配置主键-->
     <id name="cardNum">
       <!--这个相当于告诉他我自己写主键的值-->
       <generator class="assigned"></generator>
     </id>
     <!--配置其他的字段-->
     <property name="cardTime"></property>
    
    <!--配置一对一的关系了
            有外键的一方  必须先要配置成many-to-one
    -->
     <many-to-one name="user" class="User" column="u_id" cascade="all"></many-to-one>
   </class>
</hibernate-mapping>
 5>:测试类
	@Test
	public void testOne2One() throws Exception {
		//如果是基于外键映射的话那么只能通过有外键的一方来维护没有外键的这一方
		//获取我们的Session对象
		Session session=getSession();
		
		User user=new User();
		user.setuAddress("四川成都...");
		user.setuName("小波波");
		IdCard idCard=new IdCard();
		idCard.setCardNum("510.....7890");
		idCard.setCardTime(new Date(1234));
		idCard.setUser(user);
		session.save(idCard);		
		close();
	}

  基于主键来进行映射(就是将用户表的主键作为身份证表的主键)

  1>:用户的实体如下
public class User {
	private int uId;   
	private String uName;   
	private String uAddress;
	private IdCard idCard;
        setter...
        getter...
}
  2>:身份证的实体设计如下
public class IdCard {
	private String cardNum;    //身份证号码
	private Date cardTime;     //身份证的有效时间
	private User user;         //一个身份证对应了一个用户
	//如果是基于主键来进行映射的话那么这里还需要一个字段  就是另外一个表的外键字段
	private int uId;    //这个就是我们维护的外键
       setter...
       getter...
}
  3>:用户的映射文件如下
<!--这里的package用来指定实体所在的包
         这里的这个package是用来存放我们的实体类所在的包的
         如果这里省略的话那么就需要在class的name上面编写全路径
-->
<hibernate-mapping package="com.qf.one2one1">
   
   <class name="User">
     <!--配置主键-->
     <id name="uId">
       <generator class="native"></generator>
     </id>
     <!--配置其他的字段-->
     <property name="uAddress"></property>
     <property name="uName"></property>
     
      <!--配置一对一的映射的时候分为 有外键的一方和没有外键的一方-->
      <!--没有外键的这一方-->
      <one-to-one name="idCard" class="com.qf.one2one1.IdCard" cascade="all"></one-to-one>
   </class>
</hibernate-mapping>
  4>:身份证的映射关系如下
<!--这里的package用来指定实体所在的包
         这里的这个package是用来存放我们的实体类所在的包的
         如果这里省略的话那么就需要在class的name上面编写全路径
-->
<hibernate-mapping package="com.qf.one2one1">
   <class name="IdCard">
     <id name="uId">
        <!--
                            这里表示的是这个值是通过外键生成的
        -->
        <generator class="foreign">
            <!--parame中的这个名字key是不能改变
                                    后面的值写的是我们下面的配置的一对一中的这个实体的名字
            -->  
            <param name="property">user</param>
        </generator>
     </id>
     <!--配置其他的字段-->
     <property name="cardTime"></property>
     <property name="cardNum"></property>
     <!--
         constrained="true":这个表示的是给主键添加外键约束
     -->
     <one-to-one cascade="all" name="user" constrained="true"  class="com.qf.one2one1.User"></one-to-one>
   </class>
</hibernate-mapping>
  5>:测试类如下
	@Test
	public void testOne2One() throws Exception {
		//如果是基于外键映射的话那么只能通过有外键的一方来维护没有外键的这一方
		//获取我们的Session对象
		Session session=HibernateUtils.getSession();
		User user=new User();
		user.setuAddress("四川成都...");
		user.setuName("小波波");
		IdCard idCard=new IdCard();
		idCard.setCardNum("510.....7890");
		idCard.setCardTime(new Date(1234));
		idCard.setUser(user);
		session.save(idCard);
		HibernateUtils.close();
	}

4>:一对多映射

      需求:使用Hibernate描述部门和员工之间的关系(一个部门有多个员工   部门和员工之间的关系:一对多)

   1>:描述部门的实体如下
public class Dept implements Serializable{
	private int dId;
	private String dName;
	private String dDes;
	private String dAddress;
	private String dTelNum;
	//一个部门有多个员工
	private Set<Employee> emps=new HashSet<Employee>();
        setter...
        getter...
}
    2>:描述员工的实体如下
public class Employee implements Serializable{
	private int eId;
	private String eName;
	private String eTelNum;
	private String eAddress;
	private Dept dept;
        setter...
        getter..
}.
    3>:部门的映射文件如下
<hibernate-mapping package="com.qf.one2many">
   <class name="Dept" table="t_dept">
     <!--配置主键-->
     <id name="dId" column="d_id">
       <generator class="native"></generator>
     </id>
     <!--配置其他的字段-->
     <property name="dDes" column="d_des" length="30"></property>
     <property name="dTelNum" column="d_tel" length="11"></property>
     <property name="dName" column="d_name" length="10"></property>
     <property name="dAddress" column="d_address" length="50"></property>
   
     <!--接下来配置我们的一对多的映射
                       这里如果你要写这个表的话那么这个表的名字就要和 employ.hbm.xml中的表明保持一致
     -->
     <set name="emps" table="t_emp" cascade="save-update" >
       <!--这个对应的是class中的主键-->
       <key column="d_id"></key>
       <!--一对多就不能写element了-->
       <one-to-many class="Employee"/>
     </set>
   </class>
</hibernate-mapping>
  3>:员工的映射文件如下
<!--这里的package用来指定实体所在的包
         这里的这个package是用来存放我们的实体类所在的包的
         如果这里省略的话那么就需要在class的name上面编写全路径
-->
<hibernate-mapping package="com.qf.one2many">
   <class name="Employee" table="t_emp">
      <!--配置的是主键-->
      <id name="eId">
        <generator class="native"></generator>
      </id>
      
      <!--配置的是普通字段-->
      <property name="eName" length="10"></property>
      <property name="eTelNum" length="10"></property>
      <property name="eAddress" length="11"></property>
      
      <!--下面就可以配置多对一的关联关系了..-->
      <many-to-one name="dept" column="d_id" cascade="all"></many-to-one>
   </class>
</hibernate-mapping>
   4>:测试文件如下
public class Test_002 {
	/**
	 * 测试下List集合
	 * @Title: testList 
	 * @Description: TODO
	 * @param @throws Exception    
	 * @return void    
	 * @throws
	 */
	@Test
	public void testOne2Many() throws Exception {
		
		Session session=HibernateUtils1.getSession();
		
		//初始化员工
		Employee employee=new Employee();
		employee.seteAddress("xxx");
		employee.seteName("开发部");
		employee.seteTelNum("112");
		
		Employee employee1=new Employee();
		employee1.seteAddress("xxx");
		employee1.seteName("开发部");
		employee1.seteTelNum("112");
		
		Employee employee2=new Employee();
		employee2.seteAddress("xxx");
		employee2.seteName("开发部");
		employee2.seteTelNum("112");
		
		Employee employee3=new Employee();
		employee3.seteAddress("xxx");
		employee3.seteName("开发部");
		employee3.seteTelNum("112");
		
		
		Set<Employee> emps=new HashSet<Employee>();
		emps.add(employee);
		emps.add(employee1);
		emps.add(employee2);
		emps.add(employee3);
		
		Dept dept=new Dept();
		dept.setdAddress("18楼3教室");
		dept.setdDes("JAVA教学部负责JAVA");
		dept.setdName("JAVA教学部");
		dept.setdTelNum("110");
		dept.setEmps(emps);
		
		
		session.save(dept);

		HibernateUtils1.close();
	}
	
	
	@Test
	public void testMany2One() throws Exception {
		
		Session session=HibernateUtils1.getSession();
		
		//因为配置了员工和部门之间的关系 所以这里是可以通过员工来维护部门的
		// 维护  :维护的是关联关系  这个所谓的关键关系指的是  两个表之间关联的字段
		Employee employee=new Employee();
		employee.seteAddress("xxx");
		employee.seteName("铁蛋小");
		employee.seteTelNum("112");
		
	
			
		Dept dept=new Dept();
		dept.setdAddress("ddd");
		dept.setdDes("dddxxx");
		dept.setdTelNum("120");
		dept.setdName("开发部111");
		employee.setDept(dept);
		
		//最后进行保存数据
		session.save(employee);
		
		
		HibernateUtils1.close();
	}
	
}

5>:多对多映射

      需求:使用Hibernate描述程序员和项目之间的关系(一个程序员可以开发多个项目,一个项目可以被多个程序员来开发)

      程序员------->项目    一对多

      项目----------->程序员 一对多

     综上所述:程序员和项目 (多对多)

  1>:程序员的实体描述
public class Developer implements Serializable{
	private int dId;
	private String dName;
	private String dTelNum;
	private Set<Project> projects=new HashSet<Project>();

        setter...
        getter..
}.
   2>:项目的实体描述
public class Project implements Serializable{
	private int pId;
	private String pName;
	private String pDes;
	private Date startTime;
	private Date endTime;
	private Set<Developer> developers=new HashSet<Developer>();

        setter...
        getter..
}.
3>:程序员映射文件
<!--这里的package用来指定实体所在的包
         这里的这个package是用来存放我们的实体类所在的包的
         如果这里省略的话那么就需要在class的name上面编写全路径
-->
<hibernate-mapping package="com.qf.many2many" default-lazy="false">
   
   <class name="Developer" table="t_dev">
     <!--配置主键-->
     <id name="dId" column="d_id">
       <generator class="native"></generator>
     </id>
     <!--配置其他的字段-->
     <property name="dName" column="d_name"></property>
     <property name="dTelNum" column="d_telnum"></property>
   
     <!--这里就开始配置多对多的关联
         table:配置的是中间表的名字
         lazy="true":这句话的作用是支持懒加载
         lazy="false"
     -->
     <set name="projects" table="t_relation"  cascade="all" inverse="false">
        <!--配置映射到class的主键的字段-->
        <key column="d_id"></key>
        <!--配置多对多
            class:代表的是多对多对方的这个class 
            column:代表的是对方class类里面的主键在关系表里面的列的名字
        -->
        <many-to-many class="Project" column="p_id"></many-to-many>
     </set>
   </class>
</hibernate-mapping>
  4>:项目的映射文件
<!--这里的package用来指定实体所在的包
         这里的这个package是用来存放我们的实体类所在的包的
         如果这里省略的话那么就需要在class的name上面编写全路径
-->
<hibernate-mapping package="com.qf.many2many">
   
   <class name="Project" table="t_pro">
     <!--配置主键-->
     <id name="pId" column="p_id">
       <generator class="native"></generator>
     </id>
     <!--配置其他的字段-->
     <property name="endTime"></property>
     <property name="startTime"></property>
     <property name="pName" column="p_name" ></property>
     <property name="pDes" column="p_des" ></property>
   
   
     <!--配置多对多的关联关系-->
     <!-- <set name="developers" table="t_relation">
        映射当前类的key
        <key column="p_id"></key>
        配置我们的多对多的关联关系
        <many-to-many class="Developer" column="d_id"></many-to-many>
     </set> -->
   </class>
</hibernate-mapping>
  5>:测试文件如下
@Test
	public void testMany2Many() throws Exception {
		Session session=HibernateUtils.getSession();	
		//首先准备Project
		Project project=new Project();
		project.setEndTime(new Date(1233444));
		project.setStartTime(new Date(1233444));
		project.setpName("医院床边信息娱乐系统");
		project.setpDes("医院娱乐用的...");
		
		Project project1=new Project();
		project1.setEndTime(new Date(1233444));
		project1.setStartTime(new Date(1233444));
		project1.setpName("医院床边信息娱乐系统111");
		project1.setpDes("医院娱乐用的...111");
		
		Project project2=new Project();
		project2.setEndTime(new Date(1233444));
		project2.setStartTime(new Date(1233444));
		project2.setpName("医院床边信息娱乐系统222");
		project2.setpDes("医院娱乐用的...222");
		
		Project project3=new Project();
		project3.setEndTime(new Date(1233444));
		project3.setStartTime(new Date(1233444));
		project3.setpName("医院床边信息娱乐系统333");
		project3.setpDes("医院娱乐用的...333");
	
		Developer developer=new Developer();
		developer.setdName("铁蛋");
		developer.setdTelNum("120");
		developer.getProjects().add(project);
		developer.getProjects().add(project1);
		developer.getProjects().add(project2);
		developer.getProjects().add(project3);	
		//这里进行save保存
		session.save(developer);
		
		HibernateUtils.close();
	}
	

 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值