Hibernate学习笔记:一对多的关联关系(one-to-many) 双向关联

对多的关联关系也是最常见的对象之间的关系, 比如一个班级有很多个学生, 一个公司有很多部门,一个部门有很多雇员,一份债务(Credit)对应多个现金流(Cashflow),一个人有多个小孩, 一个客户有多张订单等等。
为了演示one-to-many,继续重用前面的对象Member会员,一个Member对象可以下多个订单Order,先添加一个订单类:

view plaincopy to clipboardprint?
package model;  
import java.util.Set;  
public class Order {  
 private int id;  
 private float totalPrice;  
 
//getter and setter ignored  
 
 public Order(){}  
   
 public Order(int id, float totalPrice, Member member){  
  this.id = id;  
  this.totalPrice = totalPrice;  
  //this.member = member;  
 }  
 
 public String toString(){  
  return "/nid: " + id + "/ntotal price: " + totalPrice;   
 
 }  
 

package model;
import java.util.Set;
public class Order {
 private int id;
 private float totalPrice;

//getter and setter ignored

 public Order(){}
 
 public Order(int id, float totalPrice, Member member){
  this.id = id;
  this.totalPrice = totalPrice;
  //this.member = member;
 }

 public String toString(){
  return "/nid: " + id + "/ntotal price: " + totalPrice;

 }

}

 

修改Member对象,给它添加一个属性orders,表示该Member对象持有的订单。

view plaincopy to clipboardprint?
package model;  
import java.util.Set;  
public class Member {  
 private int id;  
 private String name;  
 private String sex;  
 private IDCard card;  
 private Contact contact;  
 private Set<Order> orders;  
//getter and setter ignored  

package model;
import java.util.Set;
public class Member {
 private int id;
 private String name;
 private String sex;
 private IDCard card;
 private Contact contact;
 private Set<Order> orders;
//getter and setter ignored
}

 

对应的数据库中的表myorder (本来我喜欢把表名和对象名保持一致, 但是因为在sqlserver2000中order是关键字,所以用myorder作表名) 有一个字段member_id和member表的id关联。下面是dml语句和映射文件。

Member.hbm.xml:

view plaincopy to clipboardprint?
<?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> 
    <class name="model.Member" table="member"> 
        <id name="id" column="id"> 
            <generator class="native" /><!-- identity can also work --> 
        </id> 
        <property name="name" length="20" /> 
        <property name="sex" length="1" /> 
        <one-to-one name="card" class="model.IDCard" cascade="all" /> 
        <one-to-one name="contact" class="model.Contact" cascade="all" property-ref="member"/> 
        <set name="orders" cascade="all"> 
            <!-- key表明多端orders通过外键member_id和一端Member关联 --> 
            <key column="member_id" not-null="true" /> 
            <one-to-many class="model.Order" /> 
        </set> 
    </class> 
</hibernate-mapping> 
<?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>
 <class name="model.Member" table="member">
  <id name="id" column="id">
   <generator class="native" /><!-- identity can also work -->
  </id>
  <property name="name" length="20" />
  <property name="sex" length="1" />
  <one-to-one name="card" class="model.IDCard" cascade="all" />
  <one-to-one name="contact" class="model.Contact" cascade="all" property-ref="member"/>
  <set name="orders" cascade="all">
   <!-- key表明多端orders通过外键member_id和一端Member关联 -->
   <key column="member_id" not-null="true" />
   <one-to-many class="model.Order" />
  </set>
 </class>
</hibernate-mapping>

Order.hbm.xml:

view plaincopy to clipboardprint?
<?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"> 
<!--   
create table myorder(  
 id int identity(1, 1) primary key,  
 total_price float not null,  
 member_id int not null  
)   
alter table myorder add constraint fk_order_member_id  
  foreign key (member_id) references member(id)  
 --> 
<hibernate-mapping> 
 <class name="model.Order" table="myorder" schema="dbo" catalog="hibernate"> 
  <id name="id" column="id"> 
   <generator class="native" /> 
  </id> 
  <property name="totalPrice" type="java.lang.Float"> 
   <column name="total_price" not-null="true" /> 
  </property> 
 </class> 
</hibernate-mapping> 
<?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">
<!--
create table myorder(
 id int identity(1, 1) primary key,
 total_price float not null,
 member_id int not null
)
alter table myorder add constraint fk_order_member_id
  foreign key (member_id) references member(id)
 -->
<hibernate-mapping>
 <class name="model.Order" table="myorder" schema="dbo" catalog="hibernate">
  <id name="id" column="id">
   <generator class="native" />
  </id>
  <property name="totalPrice" type="java.lang.Float">
   <column name="total_price" not-null="true" />
  </property>
 </class>
</hibernate-mapping>
 

修改一下MemberHibernateDao的测试用例main函数来测试看对Member 进行操作的时候可不可以成功的操作orders。

public static void main(String[] args){  
    MemberDao dao = new MemberHibernateDao();  
    Member m = dao.getById(2);  
    for(Order o : m.getOrders()){  
        System.out.println(o);  
    }  
    Order o1 = new Order();  
    o1.setTotalPrice(444F);  
    m.getOrders().add(o1);  
    dao.save(m);  
    dao.deleteById(3);  

public static void main(String[] args){
 MemberDao dao = new MemberHibernateDao();
 Member m = dao.getById(2);
 for(Order o : m.getOrders()){
  System.out.println(o);
 }
 Order o1 = new Order();
 o1.setTotalPrice(444F);
 m.getOrders().add(o1);
 dao.save(m);
 dao.deleteById(3);
}

一切工作正常,遥测信号正常。(BS一下)。

但是有一个问题:Member和Order是一对多单向关联关系,通过Member可以获得orders, 但是通过Order却不能获得member。于是在给Member添加一个订单Order的时候, 需要先获得orders集合, 然后orders.add(new Order); 然后调save方法。而且更要命的是,观察一下hibernate输出的SQL会发现,为了添加一条order, 居然产生了两条sql语句:

insert into hibernate.dbo.myorder (total_price, member_id) values (?, ?) select scope_identity()
update hibernate.dbo.myorder set member_id=? where id=?

这样严重影响了数据库的性能。如果Order可以知道Member的存在,那问题就好办了,于是, 有了双向关联。

现在动手改善一下代码和配置文件,以形成双向关联。修改Order.java,添加一个属性member。

view plaincopy to clipboardprint?
public class Order {  
 private int id;  
 private float totalPrice;  
 private Member member;  
//getter and setter ignored  

public class Order {
 private int id;
 private float totalPrice;
 private Member member;
//getter and setter ignored
}
 

修改一下Order.hbm.xml, 使Order可以反向关联到Member:

view plaincopy to clipboardprint?
<hibernate-mapping> 
 <class name="model.Order" table="myorder" schema="dbo" catalog="hibernate"> 
  <id name="id" column="id"> 
   <generator class="native" /> 
  </id> 
  <property name="totalPrice" type="java.lang.Float"> 
   <column name="total_price" not-null="true" /> 
  </property> 
  <many-to-one name="member" class="model.Member" column="member_id" /> 
 </class> 
</hibernate-mapping> 
<hibernate-mapping>
 <class name="model.Order" table="myorder" schema="dbo" catalog="hibernate">
  <id name="id" column="id">
   <generator class="native" />
  </id>
  <property name="totalPrice" type="java.lang.Float">
   <column name="total_price" not-null="true" />
  </property>
  <many-to-one name="member" class="model.Member" column="member_id" />
 </class>
</hibernate-mapping>

 

修改一下Member.hbm.xml的orders配置,inverse="true"的意思是Member不再主控和order的关系, 由Order来控制它和Member的关系,这样的话,Order会去主动感知Member。

view plaincopy to clipboardprint?
<set name="orders" cascade="all" inverse="true"> 
   <key column="member_id" not-null="true" /> 
   <one-to-many class="model.Order" /> 
</set> 
<set name="orders" cascade="all" inverse="true">
   <key column="member_id" not-null="true" />
   <one-to-many class="model.Order" />
</set>
 

修改测试用例重新测试:

view plaincopy to clipboardprint?
public static void main(String[] args){  
 MemberDao dao = new MemberHibernateDao();  
 Member m = dao.getById(5);  
 for(Order o : m.getOrders()){  
  System.out.println(o);  
 }  
 Order o1 = new Order();  
 //Order需要主动的获取Member  
 o1.setMember(m);  
 o1.setTotalPrice(333F);  
 m.getOrders().add(o1);  
 dao.save(m);  

public static void main(String[] args){
 MemberDao dao = new MemberHibernateDao();
 Member m = dao.getById(5);
 for(Order o : m.getOrders()){
  System.out.println(o);
 }
 Order o1 = new Order();
 //Order需要主动的获取Member
 o1.setMember(m);
 o1.setTotalPrice(333F);
 m.getOrders().add(o1);
 dao.save(m);
}
 

再次观察sql输出会发现插入order只需要1条sql。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/sunxing007/archive/2009/08/22/4473813.aspx

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值