Hibernate一对多数据关联

Hibernate一对多数据关联

一对多数据关联

一.单向一对多数据关联
一个用户有多个地址,在用户类TUser中包含地址类TAddress集合。

1.数据模型

2.表定义sql
use  sample;

DROP   TABLE  T_Address;
DROP   TABLE  T_User;

CREATE   TABLE  T_User (
       id 
INT   NOT   NULL  AUTO_INCREMENT
     , name 
VARCHAR ( 50 )
     , age 
INT
     , 
PRIMARY   KEY  (id)
);

CREATE   TABLE  T_Address (
       id 
INT   NOT   NULL  AUTO_INCREMENT
     , address 
VARCHAR ( 200 )
     , zipcode 
VARCHAR ( 10 )
     , tel 
VARCHAR ( 20 )
     , type 
VARCHAR ( 20 )
     , 
user_id   INT   NOT   NULL
     , idx 
INT
     , 
PRIMARY   KEY  (id)
     , 
INDEX  ( user_id )
     , 
CONSTRAINT  FK_T_Address_1  FOREIGN   KEY  ( user_id )
                  
REFERENCES  T_User (id)
);


3.POJO类
TUser.java
package  cn.blogjava.start;

import  java.util.Set;

public   class  TUser   implements  java.io.Serializable {
    
//  Fields    
      private  Integer id;
     
private  Integer age;
     
private  String name;
     
private  Set address;


    
//  Constructors

    
public  Integer getAge() {
        
return  age;
    }

    
public   void  setAge(Integer age) {
        
this .age  =  age;
    }


    
public  Set getAddress() {
        
return  address;
    }

    
public   void  setAddress(Set address) {
        
this .address  =  address;
    }

    
/**  default constructor  */
    
public  TUser() {
    }
    
    
/**  constructor with id  */
    
public  TUser(Integer id) {
        
this .id  =  id;
    }

    
//  Property accessors

    
public  Integer getId() {
        
return   this .id;
    }
    
    
public   void  setId(Integer id) {
        
this .id  =  id;
    }

    
public  String getName() {
        
return   this .name;
    }
    
    
public   void  setName(String name) {
        
this .name  =  name;
    }
}

TAddress.java
package  cn.blogjava.start;

import  java.io.Serializable;

public   class  TAddress  implements  Serializable {
    
    
private  Integer id;
    
private  String address;
    
private  String zipcode;
    
private  String tel;
    
private  String type;
    
private  Integer userId;
    
private  Integer idx;
    
    
public  Integer getId() {
        
return  id;
    }
    
public   void  setId(Integer id) {
        
this .id  =  id;
    }
    
public  String getAddress() {
        
return  address;
    }
    
public   void  setAddress(String address) {
        
this .address  =  address;
    }
    
public  Integer getIdx() {
        
return  idx;
    }
    
public   void  setIdx(Integer idx) {
        
this .idx  =  idx;
    }
    
public  String getTel() {
        
return  tel;
    }
    
public   void  setTel(String tel) {
        
this .tel  =  tel;
    }
    
public  String getType() {
        
return  type;
    }
    
public   void  setType(String type) {
        
this .type  =  type;
    }
    
public  Integer getUserId() {
        
return  userId;
    }
    
public   void  setUserId(Integer userId) {
        
this .userId  =  userId;
    }
    
public  String getZipcode() {
        
return  zipcode;
    }
    
public   void  setZipcode(String zipcode) {
        
this .zipcode  =  zipcode;
    }

}

3.配置文件
TUser.hbm.xml
<? xml version="1.0" ?>
<! DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
>
< hibernate-mapping >
    
< class  name ="cn.blogjava.start.TUser"  table ="T_User"  catalog ="sample"
     dynamic-update
="true"  dynamic-insert ="true"
    
>
        
< id  name ="id"  type ="integer" >
            
< column  name ="id"   />
            
< generator  class ="native"   />
        
</ id >
        
< property  name ="name"  type ="string"  column ="name"   />
        
< property  name ="age"  type ="java.lang.Integer"  column ="age"   />

        
< set  name ="address"  table ="t_address"  cascade ="all"  order-by ="zipcode asc" >
            
< key  column ="user_id" >
            
</ key >
            
< one-to-many  class ="cn.blogjava.start.TAddress"   />
        
</ set >
    
</ class >
</ hibernate-mapping >

TAddress.hbm.xml
注意:没有配置user_id字段。
<? xml version="1.0" ?>
<! DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
>
< hibernate-mapping >
    
< class  name ="cn.blogjava.start.TAddress"  table ="T_Address"  catalog ="sample" >
        
< id  name ="id"  type ="integer" >
            
< column  name ="id"   />
            
< generator  class ="native"   />
        
</ id >
        
< property  name ="address"  type ="string"  column ="address"   />
        
< property  name ="zipcode"  type ="string"  column ="zipcode"   />
        
< property  name ="tel"  type ="string"  column ="tel"   />
        
< property  name ="type"  type ="string"  column ="type"   />
        
< property  name ="idx"  type ="java.lang.Integer"  column ="idx"   />
    
</ class >
</ hibernate-mapping >

4.测试代码

package  cn.blogjava.start;

import  java.util.HashSet;
import  java.util.Iterator;
import  java.util.List;

import  junit.framework.Assert;
import  junit.framework.TestCase;

import  org.hibernate.HibernateException;
import  org.hibernate.Session;
import  org.hibernate.SessionFactory;
import  org.hibernate.Transaction;
import  org.hibernate.cfg.Configuration;


public   class  HibernateTest  extends  TestCase {
    
    Session session 
=   null ;

    
protected   void  setUp() {
        
try  {
            Configuration config 
=   new  Configuration().configure();
            SessionFactory sessionFactory 
=  config.buildSessionFactory();
            session 
=  sessionFactory.openSession();
            
        } 
catch  (HibernateException e) {
            e.printStackTrace();
        }        
    }

    
protected   void  tearDown() {
        
try  {
            session.close();        
        } 
catch  (HibernateException e) {
            e.printStackTrace();
        }        
    }    
    
    
/**
     * 对象持久化测试(Insert方法)
     
*/         
    
public   void  testInsert() {
        Transaction tran 
=   null ;
        
try  {
        
            TUser user 
=   new  TUser();
            user.setName(
" byf " );
            user.setAge(
new  Integer( 26 ));
            
            TAddress addr 
=   new  TAddress();
            addr.setTel(
" 1123 " );
            addr.setZipcode(
" 233123 " );
            addr.setAddress(
" HongKong " );
            
            TAddress addr2 
=   new  TAddress();
            addr2.setTel(
" 139 " );
            addr2.setZipcode(
" 116001 " );
            addr2.setAddress(
" dalian " );            

            TAddress addr3 
=   new  TAddress();
            addr3.setTel(
" 136 " );
            addr3.setZipcode(
" 100080 " );
            addr3.setAddress(
" beijing " );
            
            
// 设置关联
            HashSet set  =   new  HashSet();
            set.add(addr);
            set.add(addr2);
            set.add(addr3);
            user.setAddress(set);
                                   
            tran 
=  session.beginTransaction();                                
            
// 插入user信息
            session.save(user);
            session.flush();
            tran.commit();
            Assert.assertEquals(user.getId().intValue()
> 0  , true );
        } 
catch  (HibernateException e) {
            e.printStackTrace();
            Assert.fail(e.getMessage());
            
if (tran  !=   null ) {
                
try  {
                    tran.rollback();
                } 
catch  (Exception e1) {
                    e1.printStackTrace();
                }
            }
        }
    }
    
    
/**
     * 对象读取测试(Select方法)
     
*/             
    
public   void  testSelect(){
        String hql 
=   "  from TUser where name='byf' " ;
        
try  {
            List userList 
=  session.createQuery(hql).list();
            TUser user 
=  (TUser)userList.get( 0 );
            System.out.println(
" user name is  "   +  user.getName());
            
            
for  (Iterator iter  =  user.getAddress().iterator(); iter.hasNext();) {
                TAddress addr 
=  (TAddress) iter.next();
                System.out.println(
" user address is  "   +  addr.getAddress());                
            }
            Assert.assertEquals(user.getName(), 
" byf " );
        } 
catch  (Exception e) {
            e.printStackTrace();
            Assert.fail(e.getMessage());
        }
    }
}

说明:
一个问题,由于是单向关联,为了保持关联关系,我们只能通过主控方对被动方进行级联更新。如果被关联方的字段为NOT NULL属性,当Hibernate创建或者更新关联关系时,可能出现约束违例。
例子中T_Address表中的user_id 为NOT NULL,如果在TAddress.hbm.xml映射了全部字段时。创建一个用户并赋予她地址信息,对于T_Address表而言,hibernate会执行两条sql语句来保存地址信息。

要执行两条SQL语句,是因为关联是单向的,就是说对于TAddress对象而言,并不知道自己应该与那一个TUser对象关联,只能先将user_id设为一个空值。
之后,根据配置文件
         < set  name ="address"  table ="t_address"  cascade ="all"  order-by ="zipcode asc" >
            
< key  column ="user_id" >
            
</ key >
            
< one-to-many  class ="cn.blogjava.start.TAddress"   />
        
</ set >
由TUser对象将自身的id赋给addr.user_id,这样导致addr属性值变动,在事物提交的时候,会进行update。

1)当save该用户的时候,
insert into t_address  (user_id, address, zipcode, tel) value (null, "HongKong", "233123", "1123")

2)当tx.commit()时:
update t_address user_id="1", address="HongKong", zipcode="233123",tel="1123" where id=2;

这样,在save user时,就会出现约束违例。

调整方法:
可以在定义数据表字段时候,不加NOT NULL约束。或者在开始为user_id随意赋一个非空值(因为还要update,不正确也没关系),或者将user_id字段从TAddress.hbm.xml中删除(本例就是这样实现)。

但是这些都是权宜之计,用两条SQL语句完成一次数据库操作,性能低下。
而双向一对多解决了这个问题。
下面来实现双向关联:
修改配置文件
TUser.hbm.xml
<? xml version="1.0" ?>
<! DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
>
< hibernate-mapping >
    
< class  name ="cn.blogjava.start.TUser"  table ="T_User"  catalog ="sample"
     dynamic-update
="true"  dynamic-insert ="true"
    
>
        
< id  name ="id"  type ="integer" >
            
< column  name ="id"   />
            
< generator  class ="native"   />
        
</ id >
        
< property  name ="name"  type ="string"  column ="name"   />
        
< property  name ="age"  type ="java.lang.Integer"  column ="age"   />

        
< set 
            
name ="address"  
            table
="t_address"  
            inverse
="true"
            cascade
="all"  
            order-by
="zipcode asc"
            
>
            
< key  column ="user_id" >
            
</ key >
            
< one-to-many  class ="cn.blogjava.start.TAddress"   />
        
</ set >
    
</ class >
</ hibernate-mapping >

设定inverse="true",表明将TUser类作为被动类,将数据关联的维护工作交给关联对象TAddress来管理。
在one-to-many模型中,将many一方设为主控方有助于性能的改善。(让总理记住每个人困难,但是每个人记住总理方便)

TAddress.hbm.xml
<? xml version="1.0" ?>
<! DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
>
< hibernate-mapping >
    
< class  name ="cn.blogjava.start.TAddress"  table ="T_Address"  catalog ="sample" >
        
< id  name ="id"  type ="integer" >
            
< column  name ="id"   />
            
< generator  class ="native"   />
        
</ id >
        
< property  name ="address"  type ="string"  column ="address"   />
        
< property  name ="zipcode"  type ="string"  column ="zipcode"   />
        
< property  name ="tel"  type ="string"  column ="tel"   />
        
< property  name ="type"  type ="string"  column ="type"   />
        
< property  name ="idx"  type ="java.lang.Integer"  column ="idx"   />
        
< many-to-one
                  
name ="user"  
                  class
="cn.blogjava.start.TUser"
                  cascade
="none"
                  outer-join
="auto"
                  update
="true"                   
                  insert
="true"
                  access
="property"
                  column
="user_id"
                  not-null
="true"
        
/>
    
</ class >
</ hibernate-mapping >

2.对TAddress.java做如下改造:
去掉user_id字段,增加user字段,和getter,setter方法。
package  cn.blogjava.start;

import  java.io.Serializable;

public   class  TAddress  implements  Serializable {
    
    
private  Integer id;
    
private  String address;
    
private  String zipcode;
    
private  String tel;
    
private  String type;
    
private  Integer idx;
    
private  TUser user;
    
    
public  TUser getUser() {
        
return  user;
    }
    
public   void  setUser(TUser user) {
        
this .user  =  user;
    }
    
public  Integer getId() {
        
return  id;
    }
    
public   void  setId(Integer id) {
        
this .id  =  id;
    }
    
public  String getAddress() {
        
return  address;
    }
    
public   void  setAddress(String address) {
        
this .address  =  address;
    }
    
public  Integer getIdx() {
        
return  idx;
    }
    
public   void  setIdx(Integer idx) {
        
this .idx  =  idx;
    }
    
public  String getTel() {
        
return  tel;
    }
    
public   void  setTel(String tel) {
        
this .tel  =  tel;
    }
    
public  String getType() {
        
return  type;
    }
    
public   void  setType(String type) {
        
this .type  =  type;
    }
    
public  String getZipcode() {
        
return  zipcode;
    }
    
public   void  setZipcode(String zipcode) {
        
this .zipcode  =  zipcode;
    }

}

4.测试代码
既然TUser不维护关联关系,需要TAddress需要自己来维护TUser,所以需要addr.setUser(user);
package  cn.blogjava.start;

import  java.util.HashSet;
import  java.util.Iterator;
import  java.util.List;

import  junit.framework.Assert;
import  junit.framework.TestCase;

import  org.hibernate.HibernateException;
import  org.hibernate.Session;
import  org.hibernate.SessionFactory;
import  org.hibernate.Transaction;
import  org.hibernate.cfg.Configuration;


public   class  HibernateTest  extends  TestCase  {
    
    Session session 
= null;

    
protected void setUp() {
        
try {
            Configuration config 
= new Configuration().configure();
            SessionFactory sessionFactory 
= config.buildSessionFactory();
            session 
= sessionFactory.openSession();
            
        }
 catch (HibernateException e) {
            e.printStackTrace();
        }
        
    }


    
protected void tearDown() {
        
try {
            session.close();        
        }
 catch (HibernateException e) {
            e.printStackTrace();
        }
        
    }
    
    
    
/** *//**
     * 对象持久化测试(Insert方法)
     
*/
        
    
public void testInsert() {
        Transaction tran 
= null;
        
try {
        
            TUser user 
= new TUser();
            user.setName(
"byf");
            user.setAge(
new Integer(26));
            
            TAddress addr 
= new TAddress();
            addr.setTel(
"1123");
            addr.setZipcode(
"233123");
            addr.setAddress(
"HongKong");
            addr.setUser(user);
            
            TAddress addr2 
= new TAddress();
            addr2.setTel(
"139");
            addr2.setZipcode(
"116001");
            addr2.setAddress(
"dalian");       
            addr2.setUser(user);

            TAddress addr3 
= new TAddress();
            addr3.setTel(
"136");
            addr3.setZipcode(
"100080");
            addr3.setAddress(
"beijing");
            addr3.setUser(user);
            
            
//设置关联
            HashSet set = new HashSet();
            set.add(addr);
            set.add(addr2);
            set.add(addr3);
            user.setAddress(set);
                                   
            tran 
= session.beginTransaction();                                
            
//插入user信息
            session.save(user);
            session.flush();
            tran.commit();
            Assert.assertEquals(user.getId().intValue()
>0 ,true);
        }
 catch (HibernateException e) {
            e.printStackTrace();
            Assert.fail(e.getMessage());
            
if(tran != null{
                
try {
                    tran.rollback();
                }
 catch (Exception e1) {
                    e1.printStackTrace();
                }

            }

        }

    }

    
    
/** *//**
     * 对象读取测试(Select方法)
     
*/
            
    
public void testSelect(){
        String hql 
= " from TUser where name='byf'";
        
try {
            List userList 
= session.createQuery(hql).list();
            TUser user 
= (TUser)userList.get(0);
            System.out.println(
"user name is " + user.getName());
            
            
for (Iterator iter = user.getAddress().iterator(); iter.hasNext();) {
                TAddress addr 
= (TAddress) iter.next();
                System.out.println(
"user address is " + addr.getAddress());                
            }

            Assert.assertEquals(user.getName(), 
"byf");
        }
 catch (Exception e) {
            e.printStackTrace();
            Assert.fail(e.getMessage());
        }

    }

}

你可能感兴趣的:(Hibernate一对多数据关联)