對象和對象之間除了繼承關(guān)系之外,還存在著關(guān)聯(lián)關(guān)系:包括分作一對一、一對多、多對一和多對多,由于這幾種關(guān)系在kodo ejb中的實現(xiàn)原理基本類似,因此本文中主要就一對一類關(guān)聯(lián)關(guān)系進行深入的講述,同時通過簡單例子的分析和實踐詳細的說明如何使用kodo ejb中提供的注釋來定義類和類之間的關(guān)聯(lián)關(guān)系,剩下的一對多、多對一和多對多三種關(guān)系將只在文章最后進行說明,請讀者參考一對一關(guān)系的實現(xiàn)過程。
  面向?qū)ο蟮氖澜缋铮恆和類b之間的一對一關(guān)系必須滿足如下條件:
  在關(guān)系數(shù)據(jù)庫中,我們通常使用唯一外鍵的方式來實現(xiàn)一對一關(guān)系,下面這個圖說明了這種的情況。
  下面開始介紹一下kodo ejb中和一對一關(guān)系實現(xiàn)相關(guān)的知識,為了說明的需要,我們首先定義一個虛擬的場景。
  模擬場景 
  我們假定要完成一個圖書館管理系統(tǒng),該系統(tǒng)中需要管理很多書,我們需要記錄書的基本信息如編號、書名、出版日期等基本信息,還需要記錄書的前言,序等信息。
  假設(shè)我們根據(jù)上面的需求,將書設(shè)計成一個類(book),包括了書的編號和名稱兩個屬性,同時將書的前言信息設(shè)計成另外一個類(bookextend),它包括了書的編號和前言信息兩個屬性。由于一本書有前言而且也不可能有其他的書前言部分會和他一樣,所以類book和bookextend之間很自然的形成了一對一的關(guān)系。這兩個類的屬性以及類之間的關(guān)系如下圖所示。
  [注]
  1、為了說明的簡單,例子設(shè)計時每個對象僅僅選擇了必要的屬性。
  2、上面的設(shè)計僅僅為了演示的要求而特意采用,不代表設(shè)計合理。
  kodo ejb中和一對一關(guān)系實現(xiàn)相關(guān)的內(nèi)容 
  在kodo ejb中,我們可以使用簡單的onetoone注釋來聲明類和類之間的一對一關(guān)系,另外可選的,我們可以使用joincolumn注釋來聲明兩個類對應(yīng)的表之間使用什么字段來進行關(guān)聯(lián)。
  onetoone 
  onetoone注釋提供了5個屬性供開發(fā)者定義類和類之間一對一關(guān)系的細節(jié)內(nèi)容。
onetoone用法舉例
public class book{ // 其他內(nèi)容… @onetoone(optional=true,cascade=cascadetype.all) public bookextend bookextend; }   joincolumn 
  joincolumn注釋用于定義主類在數(shù)據(jù)庫中對應(yīng)的表通過什么字段和關(guān)系類的主鍵進行關(guān)聯(lián),這個注釋是可選的,如果不提供該注釋,kodo在使用”對象名_id”和關(guān)聯(lián)表進行關(guān)聯(lián)(簡單情況下),比如演示場景中類book的bookextend沒有使用joincolumn注釋進行聲明,我們使用kodo ejb提供的mapping tool工具生成表格的時候,book類對應(yīng)的表book中將自動加入列bookextend_id,它的類型將和bookextend對應(yīng)表的主鍵字段id類型保持一致。
  joincolumn注釋中有兩個屬性:name和referencedcolumnname屬性。
joincolumn用法舉例
public class book{ // 其他內(nèi)容… @onetoone(optional=true,cascade=cascadetype.all) @joincolumn(name="extendid",referencedcolumnname="id") public bookextend bookextend; }   編寫符合要求的持久化類 
  現(xiàn)在我們開始根據(jù)上面章節(jié)中介紹的內(nèi)容編寫符合模擬場景中要求的book類和bookextend類,下面是作者編寫的兩個類的全部代碼,代碼中加入了比較多的注釋方便大家理解。
  book類 
package org.vivianj.kodo.examples.beans; import javax.persistence.basic; import javax.persistence.cascadetype; import javax.persistence.column; import javax.persistence.entity; import javax.persistence.generatedvalue; import javax.persistence.generationtype; import javax.persistence.id; import javax.persistence.inheritance; import javax.persistence.inheritancetype; import javax.persistence.joincolumn; import javax.persistence.onetoone; /** * book 用于表征系統(tǒng)中的書籍對象,他有三個屬性
* id - 書籍編號,書籍編號將由mysql數(shù)據(jù)庫自動生成
* name - 書名
* bookextend – 書的擴展信息,和bookextend是一對一(onetoone)關(guān)系 */ /* entity注釋表示該類是持久化類,的name屬性是該實體在查詢中對應(yīng)的唯一名稱,默認是類名 */ @entity(name = "book") /* table注釋的name屬性指定該持久化類對應(yīng)的數(shù)據(jù)表的名稱,默認數(shù)據(jù)表名和類名保持一致,為了
* 增強代碼的可移植性,建議大家在name屬性中使用大寫英文字母 */ /* inheritance注釋的strategy確定了持久化對象和數(shù)據(jù)表之間的關(guān)系,可選擇項包括single_table、joined和table_per_class,我們這里采用joined */ /* table_per_class : strategy 設(shè)置為該選項表示每個類使用一個表,也就是上面所說的第一種情況*/ /* single_table : strategy 設(shè)置為該選項表示所有類及其子類共用一個表,也就是上面所說的第二種情況*/ /* joined : strategy 設(shè)置為該選項表示每個類使用子表保存子類比父類多出的屬性,也就是上面所說的第三種情況*/ @inheritance(strategy = inheritancetype.joined) public class book { /* id注釋表示該字段是標(biāo)識字段 */ @id /* generatedvalue注釋定義了該標(biāo)識字段的產(chǎn)生方式,我們的演示系統(tǒng)中id由mysql數(shù)據(jù)庫字段自動生成,因此選擇generationtype.identity */ @generatedvalue(strategy = generationtype.identity) /* column注釋的name屬性定義了該類屬性對應(yīng)的數(shù)據(jù)字段的名稱,為了最大限度保持系統(tǒng)和數(shù)據(jù)庫之前的獨立性,建議使用大寫字符 */ @column(name = "id") public int id; /* basic注釋表示該屬性是基本屬性 */ @basic /* column注釋的name屬性定義了該類屬性對應(yīng)的數(shù)據(jù)字段的名稱,為了最大限度保持系統(tǒng)和數(shù)據(jù)庫之前的獨立性,建議使用大寫字符 */ @column(name = "name") public string name = null; /* 使用onetoone注釋表示該屬性和book類形成一對一關(guān)系,onetoone注釋的option屬性設(shè)為true表示該對象可以不存在,cascade屬性設(shè)置為cascadetype.all,表示book和bookextend對象級聯(lián)新建、更新、刪除、刷新 */ @onetoone(optional=true,cascade=cascadetype.all) /* 使用joincolumn注釋設(shè)置兩個對象對應(yīng)數(shù)據(jù)庫表之間的關(guān)聯(lián)字段 */ @joincolumn(name="extendid",referencedcolumnname="id") public bookextend bookextend; }
bookextend類
package org.vivianj.kodo.examples.beans; import javax.persistence.basic; import javax.persistence.column; import javax.persistence.entity; import javax.persistence.generatedvalue; import javax.persistence.generationtype; import javax.persistence.id; import javax.persistence.inheritance; import javax.persistence.inheritancetype; import javax.persistence.joincolumn; /** * bookextend 用于表征系統(tǒng)中書的擴展信息,他有兩個屬性:調(diào)用代碼
* id - 擴展信息編號,擴展信息編號將由mysql數(shù)據(jù)庫自動生成
* name - 書的前言信息
*/ /* entity注釋表示該類是持久化類,的name屬性是該實體在查詢中對應(yīng)的唯一名稱,默認是類名 */ @entity /* table注釋的name屬性指定該持久化類對應(yīng)的數(shù)據(jù)表的名稱,默認數(shù)據(jù)表名和類名保持一致,為了
* 增強代碼的可移植性,建議大家在name屬性中使用大寫英文字母 */ /* inheritance注釋的strategy確定了持久化對象和數(shù)據(jù)表之間的關(guān)系,可選擇項包括
* single_table、joined和table_per_class,我們這里采用joined */ /* table_per_class : strategy 設(shè)置為該選項表示每個類使用一個表,也就是上面所說的第一種情況*/ /* single_table : strategy 設(shè)置為該選項表示所有類及其子類共用一個表,也就是上面所說的第二種情況*/ /* joined : strategy 設(shè)置為該選項表示每個類使用子表保存子類比父類多出的屬性,也就是上面所說的第三種情況*/ @inheritance(strategy = inheritancetype.joined) public class bookextend { /* id注釋表示該字段是標(biāo)識字段 */ @id /* generatedvalue注釋定義了該標(biāo)識字段的產(chǎn)生方式,我們的演示系統(tǒng)中id由mysql數(shù)據(jù)庫字段自動生成,因此選擇generationtype.identity */ @generatedvalue(strategy = generationtype.identity) /* column注釋的name屬性定義了該類屬性對應(yīng)的數(shù)據(jù)字段的名稱,為了最大限度保持系統(tǒng)和數(shù)據(jù)庫之前的獨立性,建議使用大寫字符 */ @column(name = "id") public int id; /* basic注釋表示該屬性是基本屬性 */ @basic /* column注釋的name屬性定義了該類屬性對應(yīng)的數(shù)據(jù)字段的名稱,為了最大限度保持系統(tǒng)和數(shù)據(jù)庫之前的獨立性,建議使用大寫字符 */ @column(name = "name") public string name = null; }
/* 獲得ejb的實體管理器 */ entitymanagerfactory emf = persistence.createentitymanagerfactory(null); entitymanager em = emf .createentitymanager(persistencecontexttype.extended); /* 開始事務(wù) */ em.gettransaction().begin(); /* 創(chuàng)建新的book對象 */ book book = new book(); /* 設(shè)置book對象的name屬性 */ book.name = "kodo入門"; /* 創(chuàng)建新的bookextend對象 */ bookextend bookextend = new bookextend(); /* 設(shè)置對象屬性 */ bookextend.name = "spring is a very good book that ..."; /* 建立對象之間的關(guān)系 */ book.bookextend = bookextend; /* 持久化對象,只需要持久化book對象,不需要單獨持久化bookextend對象 */ em.persist(book); /* 結(jié)束事務(wù) */ em.gettransaction().commit(); em.close(); emf.close();級聯(lián)更新對象狀態(tài)
/* 獲得ejb的實體管理器 */ entitymanagerfactory emf = persistence.createentitymanagerfactory(null); entitymanager em = emf .createentitymanager(persistencecontexttype.extended); /* 開始事務(wù) */ em.gettransaction().begin(); /* 創(chuàng)建新的book對象 */ book book = new book(); /* 設(shè)置book對象的id屬性 */ book.id= 1; book.name = “kodo 入門”; /* 創(chuàng)建新的bookextend對象 */ bookextend bookextend = new bookextend(); /* 設(shè)置對象屬性 */ bookextend.id=1; bookextend.name = "kodo 分為kodo ejb和kodo jdo ..."; /* 建立對象之間的關(guān)系 */ book.bookextend = bookextend; /* 持久化對象,只需要調(diào)用book對象的merge方法,不需要單獨處理bookextend對象 */ em.merge(book); /* 結(jié)束事務(wù) */ em.gettransaction().commit(); em.close(); emf.close();級聯(lián)刪除對象
/* 獲得ejb的實體管理器 */ entitymanagerfactory emf = persistence.createentitymanagerfactory(null); entitymanager em = emf     .createentitymanager(persistencecontexttype.extended); /* 開始事務(wù) */ em.gettransaction().begin(); /* 使用查詢刪除對象,可以不必將對象加入到內(nèi)存中,提高效率 */ query q = entitymanager     .createquery("delete from book c where c.id=:id"); int id = book.id; /* 設(shè)置被刪除book對象的主鍵值 */ q.setparameter("id", id); /* 當(dāng)方法被調(diào)用時,book對象對應(yīng)的bookextend對象會同時被刪除 */ q.executeupdate(); /* 結(jié)束事務(wù) */ em.gettransaction().commit(); em.close();  emf.close();   其他幾種關(guān)聯(lián)關(guān)系新聞熱點
疑難解答
圖片精選