1. 程式人生 > >hibernate多對一關聯和一對多關聯

hibernate多對一關聯和一對多關聯

1. 多對一的單向關聯

從訂單(order)到客戶(customer)的單向關聯 (多個訂單對應一個客戶)

JavaBean: Customer

public class Customer{
	private Integer id;
	private String name;
}
JavaBean: Order
public class Order{
	private Integer id;
	private String orderNumber;
	private Double price;
	private Customer customer;   // 建立從訂單到客戶的多對一關聯
}
customer.hbm.xml:
<hibernate-mapping>
<class name="cn.itcast.many2one.Customer" table="customers">
	<id name="id" type="integer">
		<column name="id"></column>
		<generator class="increment"></generator>
	</id>
	<property name="name" type="string" access="property">
		<column name="name"></column>
	</property>
</class>
</hibernate-mapping>
order.hbm.xml:
<hibernate-mapping>
	<!-- class標籤建立javabean和表之間的對映 -->
	<class name="cn.itcast.many2one.Order" table="orders">
		<!-- id對映表中的主鍵 -->
		<id name="id" type="integer">
			<column name="id"></column>
			<!-- 配置主鍵的生成策略 -->
			<generator class="increment"></generator>
		</id>
		<!-- 
			property建立javabean中的屬性和表中列的對應關係
			type="string": string表示的是hibernate的型別,該型別是java型別和sql型別之間的橋樑
			java中的型別: String name; sql中的型別: varchar(255);
			對映一個sql的varchar型別到java的String型別
		 -->
		<!-- access屬性表示對javabean屬性的訪問策略,預設值是property  -->
		<property name="orderNumber" type="string" access="property">
			<!-- column定義表中的列    -->
			<column name="orderNumber"></column>
		</property>
		<property name="price" type="double">
			<column name="price"></column>
		</property>
		<!—
			  <many-to-one>: 使用該標籤來對映多對一關聯
			* name: 對映的持久化類中的屬性
            * class: 對映的持久化類中的屬性的型別
              cascade="save-update"   級聯儲存和更新
            * 就是將order物件所關聯的臨時物件Customer變成持久物件
              持久物件會儲存在session的一級快取中,就能插入到資料庫中
              update=”false” 指的是不能用session.update(),session.saveOrUpdate()的方式更新
              但是可以用hql語句進行更新
		-->
		<many-to-one name="customer" class="cn.itcast.many2one.Customer" cascade=”save-update”>
			<column name="customer_id" ></column>     <!-- column表示多的一方(Role)表中的外來鍵 -->
		</many-to-one>
	</class>
</hibernate-mapping>
2. 一對多的單向關聯
從客戶(customer)到訂單(order)的單向關聯 (一個客戶對應多個訂單)

JavaBean: Customer

public class Customer{
	private Integer id;
	private String name;
	private Set<Order> orders = new HashSet<Order>(0);  // 開始長度為0
}

JavaBean: Order

public class Order{
	private Integer id;
	private String orderNumber;
	private Double price;
}
Customer.hbm.xml:
<hibernate-mapping>
<class name="cn.itcast.many2one.Customer" table="customers">
	<id name="id" type="integer">
		<column name="id"></column>
		<generator class="increment"></generator>
	</id>
	<property name="name" type="string" access="property">
		<column name="name"></column>
	</property>
	<!--
		配置set集合
		Set: 使用set標籤配置客戶對應的訂單集合
		table:訂單集合中的訂單對應的表,可以不加
		cascade=”save-update”: 級聯儲存和更新,當儲存customer物件時,同時要儲存customer物件多關聯的訂單集合orders集合
        “delete”: 級聯刪除,刪除客戶的同時刪除訂單
		inverse=”true”: 表示多的一端(order端) 為主控方法      ---> 看成”全國人民”  全國人民可以記住國家主席 (多的一端說了算)
        一的一端(customer端) 不是主控方法   ---> 看成”國家主席”  國家主席是記不住全國人的
        Update的時候才有效!!! 如果不寫預設的是兩邊都維護
	-->
	<set name=”orders” table=”orders” inverse=”true”>
		<key>
			<!--對應是orders表的外來鍵,可以理解為orderes集合中的訂單物件是通過orders表的外來鍵customer_id查詢出來的-->
			<column name=”customer_id”/>
		</key>
		<!--  one-to-many表示一對多, class表示集合中存放的物件是Order物件 -->
		<one-to-many class=” cn.itcast.many2one.Order”/>
	</set>
</class>
</hibernate-mapping>
Order.hbm.xml:
<hibernate-mapping>
	<class name="cn.itcast.many2one.Order" table="orders">
		<id name="id" type="integer">
			<column name="id"></column>
			<generator class="increment"></generator>
		</id>
		<property name="orderNumber" type="string" access="property">
			<column name="orderNumber"></column>
		</property>
		<property name="price" type="double">
			<column name="price"></column>
		</property>
	</class>
</hibernate-mapping>
3. 一對多的雙向關聯
建立從Customer到Order的一對多的雙向關聯

* 從一的一端查詢關聯到多的一端

* 從多的一端查詢關聯到一的一端

* 雙向一對多和雙向多對一是兩種完全相同的情形

JavaBean: Customer

public class Customer{
	private Integer id;
	private String name;
	private Set<Order> orders = new HashSet<Order>(0);  // 開始長度為0
}
JavaBean: Order
public class Order{
	private Integer id;
	private String orderNumber;
	private Double price;
	private Customer customer;   // 建立從訂單到客戶的多對一關聯
}
Customer.hbm.xml:
<hibernate-mapping>
	<class name="cn.itcast.many2one.Customer" table="customers">
		<id name="id" type="integer">
			<column name="id"></column>
			<generator class="increment"></generator>
		</id>
		<property name="name" type="string" access="property">
			<column name="name"></column>
		</property>
		<!--
			配置set集合
			name: Customer類的orders屬性
			table: 對應表的表名
			set: 使用set標籤配置客戶對應的訂單集合
			table:訂單集合中的訂單對應的表,可以不加
			cascade=”save-update”: 級聯儲存和更新,當儲存customer物件是,同時要儲存customer物件所關聯的訂單集合Orders集合
			不要設定成cascade=”all”,因為刪除一條,其他被關聯的也會被刪除掉
			inverse:是否放棄維護表關係
			lazy:是否是懶載入,如果設定為false,則即使不使用它的子元素也會執行查詢,影響效率。
		-->
		<set name=”orders” table=”orders” cascade=”save-update”>
			<key>
				<!—對應是orders表的外來鍵,可以理解為orderes集合中的訂單物件是通過orders表的外來鍵customer_id查詢出來的-->
				<column name=”customer_id”/>
			</key>
			<!--  one-to-many表示一對多, class表示集合中存放的物件是Order物件 -->
			<one-to-many class=” cn.itcast.many2one.Order”/>
		</set>
	</class>
</hibernate-mapping>
Order.hbm.xml:
<hibernate-mapping>
	<class name="cn.itcast.many2one.Order" table="orders">
		<id name="id" type="integer">
			<column name="id"></column>
			<generator class="increment"></generator>
		</id>
		<property name="orderNumber" type="string" access="property">
			<column name="orderNumber"></column>
		</property>
		<property name="price" type="double">
			<column name="price"></column>
		</property>
		<!—
			<many-to-one>: 使用該標籤來對映多對一關聯
			* name: 對映的持久化類中的屬性
			* class: 對映的持久化類中的屬性的型別
			cascade="save-update"   級聯儲存和更新
			* 就是將order物件所關聯的臨時物件Customer變成持久物件
			  持久物件會儲存在session的一級快取中,就能插入到資料庫中
		-->
		<many-to-one name="customer" class="cn.itcast.many2one.Customer" cascade=”save-update”>
			<column name="customer_id" ></column>
		</many-to-one>
	</class>
</hibernate-mapping>
public void testDoubleRaletion(){
	Session session = sf.openSession();
	Transaction tx = session.beginTransaction();

    Order orders1=new Order();
	orders1.setOrderNumber("001");
	orders1.setPrice(20);

	Customer c=new Customer();
	c.setName("楊逍");
		
	//建立訂單和客戶的雙向關聯
	//訂單和客戶關聯
	orders1.setCustomer(c);

	//客戶和訂單關聯
	//c.getOrders().add(orders1);

	session.save(c);
	session.save(orders1);
	tx.commit();
	session.close();
}
4. 1個javabean對映2張表

一個人在網上有多張相片

對於子表中除了外來鍵,只有一列資料, 可以建立一個JavaBean對映兩個表

表的數量一般情況下和javabean的數量保持一致,但這不是絕對的,就比如我們這個例子

建表語句:

CREATE table persons(
    pid INT,
    name varchar(20)
);
CREATE table imgs(
    imgid INT,
    img varchar(20)
);
alter table persons 
add CONSTRAINT persons_pk primary key (pid);
alter table imgs 
add constraint imgs_fk foreign key imgs(imgid) references persons(pid);
JavaBean:
public class Person {
	private Integer id;
	private String name;
	private Set<String> imgs = new HashSet<String>();    // 將另一個表對映成自己的一個集合
     ... get和set方法
}
Person.hbm.xml
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.domain2">
	<class name="Person" table="persons">
		<id name="id" type="integer">
			<column name="pid"></column>
			<generator class="increment"></generator>
		</id>
		<property name="name" column="name" type="string"/>
		<!-- 以下通過一個Set元素對映Person類中的set集合
			 name是指:Person類中的成員變數名,用set對映,說明它是一個Set型別的物件
			 table:是指Person類中的成員變數imgs的資料來自於imgs表
		 -->
		<set name="imgs" table="imgs">
			<!-- 只要指定了另一個表,必須要指定另一個表中的外銉是哪一個欄位 -->
			<key column="imgid"></key>
		    <!-- 因為另一個表中,即imgs表中,除了外來鍵之外只有一個欄位,所以可以使用element元素影射
		    	element的column屬性是指items.imgs屬性的值都來自於imgs表的img欄位.
		     -->
		    <element column="imgname" type="string"></element>
		</set>
	</class>
</hibernate-mapping>

拓展: 查詢沒有圖片的人
方法1:
select pid,pname,imgname       // 查詢兩張表
from persons p left join imgs i on p.pid=i.imgid
where i.imgname is null;

方法2:
SELECT * 
FROM persons 
<span style="font-family:Comic Sans MS;">WHERE NOT EXISTS (SELECT * FROM imgs WHERE persons.pid=imgs.imgid);
</span>
5. bag和set的區別
Set:   new HashSet()  - 無序, 不能重複。 
Bag:   new ArrayList()     用bag來對映的List是無序的集合, 可以重複

          new LinkedArrayList()

配置檔案書寫略有不同:
<set name="emps" table="emp" cascade="save-update" inverse="false" lazy="true">
			<key column="edept"></key>
			<one-to-many class="Emp"/>
</set>

<bag name="cars" cascade="save-update" inverse="false">
			<key column="c_pid"/>
			<one-to-many class="Car"/>
</bag>