hibernate inverse属性

inverse的含义说得玄乎点是控制翻转,说得普通就是关系的维护有谁来做。
因为在关系数据库里面table和table之间是通过外键维护关系的(1-1,1-n),对于1-n的情况,
很显然,外键由N的一方来维护比有1的一方来维护要好,这就是OOP中的has a的关系,
用hibernate进行数据存取的时候如果在集合属性里面不设置inverse=true,那么在保存n后,
hibernate会更新外键----update TEST.Groups set PARENT_ID=? where id=?(PARENT_ID
是外键)。然而这是多余的


 Hibernate一对多双向关联及inverse的作用

       在测试Hibernate的一对多双向关联映射时,碰到很有趣的问题,跟inverse属性直接相关。

1、People.hbm.xml

< hibernate-mapping   default-lazy ="false" >   
   
< class  name ="com.persistent.People"  table ="people" >      
     
< id  name ="id"  column ="peopleId"  unsaved-value ="0" >     
        
< generator  class ="increment" >         
        
</ generator >     
     
</ id >      
     
< property  name ="name"  column ="name" ></ property >      
     
< set  name ="addresses"  cascade ="save-update" >
        
< key  column ="peopleId"  not-null ="true"   />
        
< one-to-many  class ="com.persistent.Address" />
     
</ set >      
   
</ class >
</ hibernate-mapping >

2、Address.hbm.xml

< hibernate-mapping >
  
< class  name ="com.persistent.Address"  table ="address" >   
    
< id  name ="id"  column ="addressId"  unsaved-value ="0" >
        
< generator  class ="increment" >
        
</ generator >
    
</ id >     
    
< many-to-one  name ="people"  column ="peopleId"  insert ="false"  update ="false" ></ many-to-one >     
    
< property  name ="addressName"  column ="addressName" ></ property >     
    
< property  name ="codeNumber"  column ="codeNumber" ></ property >     
  
</ class >   
</ hibernate-mapping >

3、People.java和Address.java

public   class  People  {    
  
private long id;
  
private String name;
  
private Set addresses = new HashSet();
  ...
}


public   class  Address  {    
  
private long id;
  
private People people;
  
private String addressName;
  
private String codeNumber;
  ...
}
        

4、数据库结构

  people表:{peopleId,name}

  address表:{addressId,peopleId,addressName,codeNumber}

5、测试代码

People people  =   new  People();
people.setName(
"linda " );
Address address 
=   new  Address();
address.setAddressName(
"yunnan " );
address.setCodeNumber(
" 564123 " );
address.setPeople(people);
people.getAddresses().add(address);
Session session 
=  HibernateSessionFactory.getSession();
session.beginTransaction();
session.save(people);
session.getTransaction().commit();

6、运行结果

      上面测试代码运行起来正确:

Hibernate: select max(peopleId) from people
Hibernate: select max(addressId) from address
Hibernate: insert into people (name, peopleId) values (?, ?)
Hibernate: insert into address (addressName, codeNumber, peopleId, addressId) values (?, ?, ?, ?)
Hibernate: update address set peopleId=? where addressId=?

      如果将People.hbm.xml映射改写一下:

< set  name ="addresses"  cascade ="save-update"  inverse ="true" >
        
< key  column ="peopleId"  not-null ="true"   />
        
< one-to-many  class ="com.persistent.Address" />
</ set >

      不同之处在于添加了inverse="true",结果:
Hibernate: select max(peopleId) from people
Hibernate: select max(addressId) from address
Hibernate: insert into people (name, peopleId) values (?, ?)
Hibernate: insert into address (addressName, codeNumber, addressId) values (?, ?, ?)

      可以看到,peopleId并没有写入到关联的address当中,数据库address表中相应记录的peopleId字段为空。

7、分析

      在Hibernate中,术语inverse是反转的意思,在关联关系中,inverse="false"为主控方,由主控方负责维护对象的关联关系。所以上面的映射文件改动之后,address为主控方,people为被控方,但是测试代码只进行了一个保存操作session.save(people),这是针对people的,因此无法正确级联保存address。而原来的映射文件中(虽然没有明确指明,Hibernate默认inverse="false"),people为主控方,因此保存people时它会保证关联的address的正确保存。

      也就是说,Hibernate仅仅按照主控方对象的状态的变化来同步更新数据库。按照原来的映射文件,people.getAddresses().add(address),即主控方对象的状态发生了改变,因此数据库会跟着对象状态的变化来同步更新数据库;而address.setPeople(people),即被控方对象的状态发生了改变,它是不能触发对象和数据库的同步更新的。

猜你喜欢

转载自kljjack.iteye.com/blog/1938080