对多的关联关系也是最常见的对象之间的关系, 比如一个班级有很多个学生, 一个公司有很多部门,一个部门有很多雇员,一份债务(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