一對多數(shù)據(jù)關(guān)聯(lián)
一.單向一對多數(shù)據(jù)關(guān)聯(lián)
一個用戶有多個地址,在用戶類TUser中包含地址類TAddress集合。
1.數(shù)據(jù)模型

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");
????????????
????????????//設(shè)置關(guān)聯(lián)
????????????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());
????????}
????}
}
說明:
一個問題,由于是單向關(guān)聯(lián),為了保持關(guān)聯(lián)關(guān)系,我們只能通過主控方對被動方進行級聯(lián)更新。如果被關(guān)聯(lián)方的字段為NOT NULL屬性,當Hibernate創(chuàng)建或者更新關(guān)聯(lián)關(guān)系時,可能出現(xiàn)約束違例。
例子中T_Address表中的user_id 為NOT NULL,如果在TAddress.hbm.xml映射了全部字段時。創(chuàng)建一個用戶并賦予她地址信息,對于T_Address表而言,hibernate會執(zhí)行兩條sql語句來保存地址信息。
要執(zhí)行兩條SQL語句,是因為關(guān)聯(lián)是單向的,就是說對于TAddress對象而言,并不知道自己應(yīng)該與那一個TUser對象關(guān)聯(lián),只能先將user_id設(shè)為一個空值。
之后,根據(jù)配置文件
????????
<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,這樣導(dǎo)致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時,就會出現(xiàn)約束違例。
調(diào)整方法:
可以在定義數(shù)據(jù)表字段時候,不加NOT NULL約束。或者在開始為user_id隨意賦一個非空值(因為還要update,不正確也沒關(guān)系),或者將user_id字段從TAddress.hbm.xml中刪除(本例就是這樣實現(xiàn))。
但是這些都是權(quán)宜之計,用兩條SQL語句完成一次數(shù)據(jù)庫操作,性能低下。
而雙向一對多解決了這個問題。
下面來實現(xiàn)雙向關(guān)聯(lián):
修改配置文件
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>
設(shè)定inverse="true",表明將TUser類作為被動類,將數(shù)據(jù)關(guān)聯(lián)的維護工作交給關(guān)聯(lián)對象TAddress來管理。
在one-to-many模型中,將many一方設(shè)為主控方有助于性能的改善。(讓總理記住每個人困難,但是每個人記住總理方便)
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不維護關(guān)聯(lián)關(guān)系,需要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);
????????????
????????????//設(shè)置關(guān)聯(lián)
????????????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());
????????}
????}
}
posted on 2006-07-05 15:13
knowhow 閱讀(555)
評論(1) 編輯 收藏 所屬分類:
ORM:Hibernate及其他