一对多与多对一关联关系

来源:互联网 发布:监狱建筑师 mac 汉化 编辑:程序博客网 时间:2024/06/05 07:10

一对多与多对一关联关系

在hibernate中关联关系一般都是通过外键来关联的,(我在学习的时候也有个错误的理解,这个外键不是在数据库表上建立的,经过试验在数据库中不建立外键关系,只在hibernate中设置完全可以实现同样的效果),这时的关联可以分为单向与双向两种。

所谓的单向就是说,在两端中的任一端不知知道另一端的存在,而另一端确清楚的小的另一端;双向当然就是双方互知了。

1、单向关联
在hibernate里面一对多关联关系的实现实在“一”的一段映射文件中使用<one-to-many>节点实现的,同时要求在“一”端的POJO使用集合来存储“多段”的对象。

在以下例子中我将实现一个留言板程序。
先完成数据库的一部分设计,首先需要一个表来存储用户信息,然后还需要一个表来存放留言信息,具体的SQL语句如下(我采用的是MySQL数据库):
CREATE TABLE `user` (
  `usr_id` int(11) NOT NULL auto_increment,
  `usr_name` char(20) default NULL,
  `usr_psw` char(20) default NULL,
  PRIMARY KEY  (`usr_id`)
) ENGINE=InnoDB DEFAULT CHARSET=UTF8;

CREATE TABLE `message` (
  `msg_id` int(11) NOT NULL auto_increment,
  `msg_ttl` char(20) NOT NULL default 0,
  `msg_desc` char(50) default NULL,
  `msg_date` Date,
  `usr_id` int(11)NOT NULL default 0,
  PRIMARY KEY  (`msg_id`)
) ENGINE=InnoDB DEFAULT CHARSET=UTF8;

显然这是个一对多的例子,相应的POJO类为
public class Message {
    private int msgId;
    private String ttl;
    private String desc;
private Date date;

public class UserInfo {
    private int userId;
    private String name;
    private String password;
    private IdCard idCard;
private Set messages;

这里我省了get,set方法
相应的映射文件配置:
<hibernate-mapping>
   <class name="xiaojin.hibernate.entity.UserInfo" table="USER">
      <id name="userId" type="int" column="usr_id">
         <generator class="native"/>
      </id>
      <property name="name" column="usr_name" type="string" />
      <property name="password" column="usr_psw" type="string" />
      <set name="messages" order-by="usr_id" cascade="all">
          <key column="usr_id" />
          <one-to-many class="xiaojin.hibernate.entity.Message" />
      </set>
   </class>
</hibernate-mapping>

这个配置文件最主要的就是这个节点
      <set name="messages" order-by="usr_id" cascade="all">
          <key column="usr_id" />
          <one-to-many class="xiaojin.hibernate.entity.Message" />
      </set>
这个<set>节点意味着POJO UserInfo类里面定义一个集合,在这个节点中:
<key>:指定多端的外键,与一端的主键相关联,即MESSAGE表中的usr_id
<one-to-many>:指定多端的对应的类

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-mapping
   PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN"
   "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
   <class name="xiaojin.hibernate.entity.Message" table="MESSAGE">
      <id name="msgId" type="int" column="msg_id">
         <generator class="native"/>
      </id>
      <property name="ttl" column="msg_ttl" type="string" not-null="true"/>
      <property name="desc" column="msg_desc" type="string" not-null="true"/>
      <property name="date" column="msg_date" type="string" />
多对一的映射与上面完全一样,只不过需要在多的一段进行配置,即在message的应射文件中需要配置<many-to-one>节点:
<many-to-one name="user" column="usr_id" />


2、双向关联
双向关联在两端都知道对方的存在,同时也是由“一对多”和“多对一”两个关联关系组合而成的。在实现上也就是说,POJO的两个类里面都要有一个属性来保存对方的值。
 
public class Message {
    private int msgId;
    private String ttl;
    private String desc;
    private Date date;
private UserInfo user;

这时要在“多”的一端加上<many-to-one>节点,
<many-to-one name="user" class="xiaojin.hibernate.entity.UserInfo" column="usr_id" cascade="none"></many-to-one>
其中个属性
name:标明关联的一端
column:外键
cascade:是指级联操作
在“一“的一端配置:
<set name="messages" order-by="usr_id" cascade="all" inverse="true" >
          <key column="usr_id" />
          <one-to-many class="xiaojin.hibernate.entity.Message" />
 </set>
可以看到这里加了一个属性inverse="true"  意为反转,在双向关联中inverse="false" 的一方为主动方负责维护关联关系,默认值为false
在上述配置中,主动方在message一方,也就是说在message持久化过程中,message会主动去获取相关的user 对象的usr_id 作为自己的外键usr_id。

关于级联操作:
级联操作是通过cascade来进行配置的。
从常识来讲对于级联的操作主动方都应该是以的一段的,举个例子来讲,当我们要删除一条message时是不允许其删除与之相关联的user的,然而当删除一个user必要将与其相关的message删除掉。在上面的配置中cascade="none"就是为了这个需求,当然在实际情况下还要同需求相联系来具体设置,hibernate的配置还是很灵活的。
测试方法:
    public static void saveMessagesAndUser(){
        UserInfo user= new UserInfo();
        user.setName("xiaofei");
        user.setPassword("xiaofei");
        Set<Message> msgs = new HashSet<Message>();
        Message msg = new Message();
        msg.setTtl("msg_xiaofei");
        msg.setDesc("desc");
        msgs.add(msg);
        user.setMessages(msgs);
        msg.setUser(user);
        save(user);       
}
注意上面加粗的两行,这时我们用的已经是双向关联了!

关于在应用中是应该使用单行关联还是双向关联:
hibernate的建议是使用双向关联。
关于一对多还是多对一:
多对一关联映射:在多的一端加入一个外键指向一的一端,它维护的关系是多指向一
一对多关联映射:在多的一端加入一个外键指向一的一端,它维护的关系是一指向多
也就是说一对多和多对一的映射策略是一样的,只是站的角度不同


 

原创粉丝点击