Kodo EJB:實作類別和類之間的關聯關係

來源:互聯網
上載者:User

  對象和對象之間除了繼承關係之外,還存在著關聯關係:包括分作一對一、一對多、多對一和多對多,由於這幾種關係在Kodo EJB中的實現原理基本類似,因此本文中主要就一對一類關聯關係進行深入的講述,同時通過簡單例子的分析和實踐詳細的說明如何使用Kodo EJB中提供的注釋來定義類和類之間的關聯關係,剩下的一對多、多對一和多對多三種關係將只在文章最後進行說明,請讀者參考一對一關聯性的實現過程。

  物件導向的世界裡,類A和類B之間的一對一關聯性必須滿足如下條件:

  1. 對象A1引用了對象B1

  2. 類A其他對象An不可能應用同樣的對象B1

  在關聯式資料庫中,我們通常使用唯一外鍵的方式來實現一對一關聯性,下面這個圖說明了這種的情況。



  下面開始介紹一下Kodo EJB中和一對一關聯性實現相關的知識,為了說明的需要,我們首先定義一個虛擬情境。

  類比情境

  我們假定要完成一個圖書館管理系統,該系統中需要管理很多書,我們需要記錄書的基本資料如編號、書名、出版日期等基本資料,還需要記錄書的前言,序等資訊。

  假設我們根據上面的需求,將書設計成一個類(Book),包括了書的編號和名稱兩個屬性,同時將書的前言資訊設計成另外一個類(BookExtend),它包括了書的編號和前言資訊兩個屬性。由於一本書有前言而且也不可能有其他的書前言部分會和他一樣,所以類Book和BookExtend之間很自然的形成了一對一的關係。這兩個類的屬性以及類之間的關係如下圖所示。



  [注]

  1、為了說明的簡單,例子設計時每個對象僅僅選擇了必要的屬性。

  2、上面的設計僅僅為了示範的要求而特意採用,不代表設計合理。

  Kodo EJB中和一對一關聯性實現相關的內容

  在Kodo EJB中,我們可以使用簡單的OneToOne注釋來聲明類和類之間的一對一關聯性,另外可選的,我們可以使用JoinColumn注釋來聲明兩個類對應的表之間使用什麼欄位來進行關聯。

  OneToOne

  OneToOne注釋提供了5個屬性供開發人員定義類和類之間一對一關聯性的細節內容。

  1. targetEntity

    Class類型的屬性。

    定義關係類的類型,預設是該成員屬性對應的類類型,所以通常不需要提供定義。

  2. mappedBy

    String類型的屬性。

    定義類之間的雙向關係。如果類之間是單向關係,不需要提供定義,如果類和類之間形成雙向關係,我們就需要使用這個屬性進行定義,否則可能引起資料一致性的問題。比如上面的示範情境中,我們只是定義Book類有BookExtend屬性,而BookExtend並沒有Book屬性,那麼他們是單向關係,如何BookExtend中也定義了Book屬性,那麼Book和BookExtend之間就構成了雙向關係。

  3. cascade

    CascadeType[]類型。

    該屬性定義類和類之間的級聯關係。定義的級聯關係將被容器視為對當前類對象及其關聯類別對象採取相同的操作,而且這種關係是遞迴調用的。舉個例子:Book和BookExtend有級聯關係,那麼刪除Book時將同時刪除它所對應的BookExtend對象。而如果BookExtend還和其他的對象之間有級聯關係,那麼這樣的操作會一直遞迴執行下去。

    cascade的值只能從CascadeType.PERSIST(級聯建立)、CascadeType.REMOVE(串聯刪除)、CascadeType.REFRESH(級聯重新整理)、CascadeType.MERGE(串聯更新)中選擇一個或多個。還有一個選擇是使用CascadeType.ALL,表示選擇全部四項。

  4. fatch

    FetchType類型的屬性。

    可選擇項包括:FetchType.EAGER和FetchType.LAZY。前者表示關係類在主類載入的時候同時載入,後者表示關係類在被訪問時才載入。預設值是FetchType.EAGER。

  5. optional

    boolean類型的屬性。

    定義該關聯類別對是否必須存在。如果設定為false,那麼該屬性就不能設定為null。預設值是true。

  OneToOne用法舉例

public class Book{ // 其他內容… @OneToOne(optional=true,cascade=CascadeType.ALL) public BookExtend bookExtend; } 

  JoinColumn

  JoinColumn注釋用於定義主類在資料庫中對應的表通過什麼欄位和關係類的主鍵進行關聯,這個注釋是可選的,如果不提供該注釋,Kodo在使用”對象名_ID”和關聯表進行關聯(簡單情況下),比如示範情境中類Book的bookExtend沒有使用JoinColumn注釋進行聲明,我們使用Kodo EJB提供的Mapping Tool工具產生表格的時候,Book類對應的表Book中將自動加入列bookExtend_ID,它的類型將和BookExtend對應表的主鍵欄位id類型保持一致。

  JoinColumn注釋中有兩個屬性:name和referencedColumnName屬性。

  1. name

    String類型。

    它用於指定主類對應的表中和關係類的主鍵進行關聯的欄位的名稱,比如上例中,我們不希望使用預設的bookExtend_ID欄位名進行關聯,我們可以在Book類中使用JoinColumn注釋bookExtend屬性,設定JoinColumn注釋為自己想要的名字比如extendID或者其他。

  2. referencedColumnName

    String類型。

    指定關聯表中與主表形成關聯關係的欄位名。主要用於設定區別於主鍵欄位的情況。比如BookExtend表中預設使用Id進行關聯,但現在需要使用其他欄位進行關聯,我們就可以提供該屬性。

  JoinColumn用法舉例

public class Book{ // 其他內容… @OneToOne(optional=true,cascade=CascadeType.ALL) @JoinColumn(name="extendID",referencedColumnName="ID") public BookExtend bookExtend; } 

  編寫符合要求的持久化類

  現在我們開始根據上面章節中介紹的內容編寫符合類比情境中要求的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 用於表徵系統中的書籍對象,他有三個屬性
* id - 書籍編號,書籍編號將由MySQL資料庫自動產生
* name - 書名
* bookExtend – 書的擴充資訊,和BookExtend是一對一(OneToOne)關係 */ /* Entity注釋表示該類是持久化類,的name屬性是該實體在查詢中對應的唯一名稱,預設是類名 */ @Entity(name = "Book") /* Table注釋的name屬性指定該持久化類對應的資料表的名稱,預設資料表名和類名保持一致,為了
* 增強代碼的可移植性,建議大家在name屬性中使用大寫英文字母 */ /* Inheritance注釋的strategy確定了持久化對象和資料表之間的關係,可選擇項包括SINGLE_TABLE、JOINED和TABLE_PER_CLASS,我們這裡採用JOINED */ /* TABLE_PER_CLASS : strategy 設定為該選項表示每個類使用一個表,也就是上面所說的第一種情況*/ /* SINGLE_TABLE : strategy 設定為該選項表示所有類及其子類共用一個表,也就是上面所說的第二種情況*/ /* JOINED : strategy 設定為該選項表示每個類使用子表儲存子類比父類多出的屬性,也就是上面所說的第三種情況*/ @Inheritance(strategy = InheritanceType.JOINED) public class Book { /* Id注釋表示該欄位是識別欄位 */ @Id /* GeneratedValue注釋定義了該識別欄位的產生方式,我們的示範系統中id由MySQL資料庫欄位自動產生,因此選擇GenerationType.IDENTITY */ @GeneratedValue(strategy = GenerationType.IDENTITY) /* Column注釋的name屬性定義了該類屬性對應的資料欄位的名稱,為了最大限度保持系統和資料庫之前的獨立性,建議使用大寫字元 */ @Column(name = "ID") public int id; /* Basic注釋表示該屬性是基本屬性 */ @Basic /* Column注釋的name屬性定義了該類屬性對應的資料欄位的名稱,為了最大限度保持系統和資料庫之前的獨立性,建議使用大寫字元 */ @Column(name = "NAME") public String name = null; /* 使用OneToOne注釋表示該屬性和Book類形成一對一關聯性,OneToOne注釋的option屬性設為True表示該對象可以不存在,cascade屬性設定為CascadeType.ALL,表示Book和BookExtend對象級聯建立、更新、刪除、重新整理 */ @OneToOne(optional=true,cascade=CascadeType.ALL) /* 使用JoinColumn注釋設定兩個對象對應資料庫表之間的關聯欄位 */ @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 用於表徵系統中書的擴充資訊,他有兩個屬性:
* id - 擴充資訊編號,擴充資訊編號將由MySQL資料庫自動產生
* name - 書的前言資訊
*/ /* Entity注釋表示該類是持久化類,的name屬性是該實體在查詢中對應的唯一名稱,預設是類名 */ @Entity /* Table注釋的name屬性指定該持久化類對應的資料表的名稱,預設資料表名和類名保持一致,為了
* 增強代碼的可移植性,建議大家在name屬性中使用大寫英文字母 */ /* Inheritance注釋的strategy確定了持久化對象和資料表之間的關係,可選擇項包括
* SINGLE_TABLE、JOINED和TABLE_PER_CLASS,我們這裡採用JOINED */ /* TABLE_PER_CLASS : strategy 設定為該選項表示每個類使用一個表,也就是上面所說的第一種情況*/ /* SINGLE_TABLE : strategy 設定為該選項表示所有類及其子類共用一個表,也就是上面所說的第二種情況*/ /* JOINED : strategy 設定為該選項表示每個類使用子表儲存子類比父類多出的屬性,也就是上面所說的第三種情況*/ @Inheritance(strategy = InheritanceType.JOINED) public class BookExtend { /* Id注釋表示該欄位是識別欄位 */ @Id /* GeneratedValue注釋定義了該識別欄位的產生方式,我們的示範系統中id由MySQL資料庫欄位自動產生,因此選擇GenerationType.IDENTITY */ @GeneratedValue(strategy = GenerationType.IDENTITY) /* Column注釋的name屬性定義了該類屬性對應的資料欄位的名稱,為了最大限度保持系統和資料庫之前的獨立性,建議使用大寫字元 */ @Column(name = "ID") public int id; /* Basic注釋表示該屬性是基本屬性 */ @Basic /* Column注釋的name屬性定義了該類屬性對應的資料欄位的名稱,為了最大限度保持系統和資料庫之前的獨立性,建議使用大寫字元 */ @Column(name = "NAME") public String name = null; }
   調用代碼

  上面的代碼中,我們已經準備好了符合要求的持久化類,下面我們看看Kodo EJB中如何調用這兩個類完成Book類和BookExtend類的建立、修改、刪除工作。

  由於篇幅的關係,這些沒有講述如何編譯、加強這些類並且準備相應的設定檔來完成整個項目開發環境的建立,這部分的內容請參考我的另外一篇文章《 Kodo EJB:符合EJB3規範的持久層架構

   級聯建立對象

  下面的這段代碼示範了只需要調用Book類的persist方法就同時持久化Book類對象和BookExtend類對象的情況。請注意其中用粗體標識出的部分。
/* 獲得EJB的實體管理器 */ EntityManagerFactory emf = Persistence.createEntityManagerFactory(null); EntityManager em = emf     .createEntityManager(PersistenceContextType.EXTENDED); /* 開始事務 */ em.getTransaction().begin();    /* 建立新的Book對象 */ Book book = new Book(); /* 設定Book對象的name屬性 */ book.name = "Kodo入門"; /* 建立新的BookExtend對象 */ BookExtend bookExtend = new BookExtend(); /* 設定對象屬性 */ bookExtend.name = "Spring is a very good book that ..."; /* 建立對象之間的關係 */ book.bookExtend = bookExtend; /* 持久化對象,只需要持久化Book對象,不需要單獨持久化bookExtend對象 */ em.persist(book); /* 結束事務 */ em.getTransaction().commit(); em.close(); emf.close(); 
   串聯更新對象狀態

  下面的這段代碼示範了只需要調用Book類的merge方法就同時更新Book類對象和BookExtend類對象狀態的情況。請注意其中用粗體標識出的部分。
/* 獲得EJB的實體管理器 */ EntityManagerFactory emf = Persistence.createEntityManagerFactory(null); EntityManager em = emf     .createEntityManager(PersistenceContextType.EXTENDED); /* 開始事務 */ em.getTransaction().begin();    /* 建立新的Book對象 */ Book book = new Book(); /* 設定Book對象的id屬性 */ book.id= 1; book.name = “Kodo 入門”; /* 建立新的BookExtend對象 */ BookExtend bookExtend = new BookExtend(); /* 設定對象屬性 */ bookExtend.id=1; bookExtend.name = "Kodo 分為Kodo EJB和Kodo JDO ..."; /* 建立對象之間的關係 */ book.bookExtend = bookExtend; /* 持久化對象,只需要調用Book對象的merge方法,不需要單獨處理bookExtend對象 */ em.merge(book); /* 結束事務 */ em.getTransaction().commit(); em.close();  emf.close(); 
  串聯刪除對象
/* 獲得EJB的實體管理器 */ EntityManagerFactory emf = Persistence.createEntityManagerFactory(null); EntityManager em = emf     .createEntityManager(PersistenceContextType.EXTENDED); /* 開始事務 */ em.getTransaction().begin(); /* 使用查詢刪除對象,可以不必將對象加入到記憶體中,提高效率 */ Query q = entityManager     .createQuery("delete from Book c WHERE c.id=:id"); int id = book.id; /* 設定被刪除Book對象的主索引值 */ q.setParameter("id", id); /* 當方法被調用時,Book對象對應的BookExtend對象會同時被刪除 */ q.executeUpdate(); /* 結束事務 */ em.getTransaction().commit(); em.close();  emf.close(); 
   其他幾種關聯關係

  一對多

  我們可以使用OneToMany注釋來描述類和類之間的一對多關聯性,OneToMany注釋有四個屬性:targetEntity、mappedBy、cascade和fetch,這四個屬性的具體含義和OneToOne注釋注釋的同名屬性一一對應,請大家參考前面章節中的內容。

  多對一

  我們可以使用ManyToOne注釋來描述類和類之間的多對一關聯性,ManyToOne注釋有四個屬性:targetEntity、cascade、fetch和optional,這四個屬性的具體含義和OneToOne注釋注釋的同名屬性一一對應,請大家參考前面章節中的內容。

  多對多

  我們可以使用ManyToMany注釋來描述類和類之間的多對多關係,ManyToMany注釋有四個屬性:targetEntity、mappedBy、cascade和fetch,這四個屬性的具體含義和OneToOne注釋注釋的同名屬性一一對應,請大家參考前面章節中的內容。

   總結

  對象和對象之間除了繼承關係之外,還存在著關聯關係,包括一對一、一對多、多對一和多對多的關係,本文中,作者以一對一關聯性為例,結合簡單的例子,詳細地描述了如何在Kodo EJB架構下通過注釋簡單的描述類和類之間的關係,並且實作類別操作的級聯特性。文章的最後簡單的說明了Kodo EJB中實現一對多、多對一和多對多時需要用到的注釋,具體的實現請大家參考文檔中的內容自行完成。

相關文章

Cloud Intelligence Leading the Digital Future

Alibaba Cloud ACtivate Online Conference, Nov. 20th & 21st, 2019 (UTC+08)

Register Now >

Starter Package

SSD Cloud server and data transfer for only $2.50 a month

Get Started >

Alibaba Cloud Free Trial

Learn and experience the power of Alibaba Cloud with a free trial worth $300-1200 USD

Learn more >

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。