JAVA認證:數(shù)據(jù)庫相關(guān)之精彩的ORM映射框架

字號:

說起持久層框架或方案,最先想到的肯定是Entity Bean,受過Entity Bean折磨的朋友都知道,其非常的不簡單的同時,也非常的不簡約。不管是CMP還是BMP的Entity Bean,曾經(jīng)讓J2EE用來作顯耀資本的Entity Bean今天回過頭去看就像一個怪胎,甚至會有一種讓人哭笑不得的感覺。EBJ3.0中推出的JPA,終結(jié)了“輕量與重量持久之爭”的同時,也宣判了Entity Bean的死刑,基于Entity Bean造價昂貴的系統(tǒng)也成了遺留系統(tǒng)。
    輕量級持久化解決方案設(shè)想的萌芽、成形、廣泛應用到最終到打敗Entity Bean的這一過程,給我們揭示了很多現(xiàn)代科學技術(shù)發(fā)展的客觀規(guī)律,我認為其中一個規(guī)律可以概括為:“簡約而不簡單”。通過最簡約的表達手段達到的表達效果一直是各個不同領(lǐng)域的創(chuàng)造者的目的,軟件也不例外同,因此“簡約主義(英文:minimalism)”應該是我們軟件設(shè)計的基本思想之一
    相對于Entity Bean,輕量級持久化方案顯得就“簡約”了許多。不依賴于任何框架的純POJO,即方便領(lǐng)域建模,也方便單元測試,更方便移植、維護及擴展。然而,在JDK1.5以前,面對輕量級ORM中的那一堆繁雜的配置文件,如何有效管理卻是讓人非常頭痛;盡管一些ORM系統(tǒng)通過引入Jakarta Commons Attributes或類似的思想來實現(xiàn)源碼級標簽聲明持久層對象映射,零亂的標簽定義仍然無法從根本上改善映射屬性配置信息管理維護的復雜性。
    JDK1.5以后,注解(Annotation)的引入為我們提供了一種非常好的源碼級配置處理方式。因此,在各種項目中得到了非常好的引用,使得持久層的方案更加簡約。特別是JPA,可算是“簡約”持久層的一個里程碑。因此,現(xiàn)在再來像Spring的Rod Johnson大叔前兩年那樣再來談怎么滅掉EJB,難免會有點滑稽可笑。
    Hibernate3.2已經(jīng)實現(xiàn)了JPA,還有很多的持久層ORM框架也將會實現(xiàn)JPA,因此您如果使用這些框架仍然可以在升級版本中享受其一定的簡約。然而“簡約”是無盡頭的,永遠無法輕易達到一種完美的境界,JPA也是如此。
    這里使用EasyDBO框架,舉一個簡單的例子,來演示“簡約”追求的過程。
    可以不需要使用配置文件,直接使用Java注解標簽,通過下面的方式定義持久層對象:
    @Table(tableName = " OrderInfo " )
    public class Order implements Serializable {
    @TableField(name = " id " )
    private Number id; // 主鍵id
    @TableField(name = " sn " )
    private String sn; // 定單編號
    @TableField(name = " vdate " )
    private Date vdate; // 定單日期
    @TableField(name = " requireDate " )
    private Date requireDate; // 交付日期
    @TableField(name = " payType " )
    private String payType; // 支付方式
    @TableField(name = " linkMan " )
    private String linkMan; // 聯(lián)系人
    @TableField(name = " tel " )
    private String tel; // 電話
    @TableField(name = " address " )
    private String address; // 地址
    @TableField(name = " requirement " )
    private String requirement; // 需求描述
    @TableField(name = " remark " )
    private String remark; // 備注
    @TableField(name = " amount " )
    private BigDecimal amount; // 訂單總金額
    @TableField(name = " handPerson " )
    private String handPerson; // 經(jīng)手人
    @TableField(name = " inputUser " )
    private String inputUser; // 錄入人
    @TableField(name = " inputTime " )
    private Date inputTime; // 錄入時間
    @TableField(name = " opUser " )
    private String opUser; // 操作人
    @TableField(name = " opIntro " )
    private String opIntro; // 操作簡介
    @TableField(name = " opTime " )
    private Date opTime; // 操作時間
    @TableField(name = " status " )
    private Integer status; // 訂單狀態(tài)
    @TableField(name = " payment " )
    private Integer payment; // 支付狀態(tài)
    @OneToOne(column = " customer_id " , type = Customer. class )
    private Customer customer; // 一對一關(guān)聯(lián),定單對應的客戶
    @ManyToOne(column = " order_id " , type = OrderDetail. class )
    private Set < OrderDetail > children = new HashSet < OrderDetail > (); // 一對多關(guān)聯(lián),定單下面的詳細信息
    public Number getId() {
    return id;
    }
    public void setId(Number id) {
    this .id = id;
    }
    public String getAddress() {
    return address;
    }
    …省略后面普通的getter及setter
    }
    由于不再需要使用配置文件,通過源碼級的Java注解標簽來標識映射關(guān)系,確實要簡單多了,而且也非常方便開發(fā)工具識別。然而,如果寫多了,你會發(fā)現(xiàn),那么多重復的標簽,而且大多數(shù)內(nèi)容又相同或類似,依靠代碼生成工具總不是辦法。比如@TableField(name=”XXX”),其中,XXX有80%以上都是屬性的字段的名稱,因此ORM系統(tǒng)應該要提供這些默認配置。下面是刪除掉所有重復、規(guī)律一致標簽后的持久層對象Order的改進寫法:
    @Table(tableName = " OrderInfo " )
    public class Order implements Serializable {
    @OneToOne(column = " customer_id " , type = Customer. class )
    private Customer customer; // 一對一關(guān)聯(lián),定單對應的客戶
    @ManyToOne(column = " order_id " , type = OrderDetail. class )
    private Set < OrderDetail > children = new HashSet < OrderDetail > (); // 一對多關(guān)聯(lián),定單下面的詳細信息
    private Number id; // 主鍵id
    private String sn; // 定單編號
    private Date vdate; // 定單日期
    private Date requireDate; // 交付日期
    private String payType; // 支付方式
    private String linkMan; // 聯(lián)系人
    private String tel; // 電話
    private String address; // 地址
    private String requirement; // 需求描述
    private String remark; // 備注
    private BigDecimal amount; // 訂單總金額
    private String handPerson; // 經(jīng)手人
    private String inputUser; // 錄入人
    private Date inputTime; // 錄入時間
    private String opUser; // 操作人
    private String opIntro; // 操作簡介
    private Date opTime; // 操作時間
    private Integer status; // 訂單狀態(tài)
    private Integer payment; // 支付狀態(tài)
    public Number getId() {
    return id;
    }
    public void setId(Number id) {
    this .id = id;
    }
    …省略后面普通的getter及setter
    }
    當然,在上面的POJO中,除了一對一、一對多等關(guān)聯(lián)需要進行標注以外,其它的都是使用數(shù)據(jù)表字段名與對象的屬性名相同的映射。追求完美的你還會提出,@OneToOne標簽也應該是可省的,另外,表名、多表映射、關(guān)聯(lián)字段等都可以再進一步“簡約”,更多復雜(“不簡單”)的處理,交由ORM框架來處理