iBATIS In Action:使用映射语句(二)
|   為IDictionary,則property是相應(yīng)key的名稱。同一property值可以出現(xiàn)多次,這取決于它在語句中出現(xiàn)的次數(shù)。  | |
|   column  |   用于定義存儲(chǔ)過程的參數(shù)名稱。  | 
|   direction  |   可用于指定存儲(chǔ)過程參數(shù)的方向。其值可以是Input,Output或InputOutput。  | 
|   dbType  |   用于顯式地指定參數(shù)對(duì)應(yīng)的列類型。對(duì)于某些操作,一些ADO.NET provider不能判斷列的類型,此時(shí)dbType必須指定。 此特性僅在列為nullable時(shí)是必需的。此外,在顯式指定日期類型時(shí)也需要此特性。盡管.NET僅有一種日期值類型(System.DateTime),大多數(shù)數(shù)據(jù)庫卻不止一個(gè)。通常情況下,數(shù)據(jù)庫至少有三種不同的日期類型(Date,DateTime,TimeStamp)。為使映射過程能夠正確,我們可能需要指定列的dbType。  | 
|   type  |   用于指定前面的property的CLR類型。在向存儲(chǔ)過程傳入InputOput和Output類型的參數(shù)時(shí),該特性很有用。 正常情況下,property的類型可通過反射獲得,但對(duì)于IDictionary類型的參數(shù)就無能為力了,此時(shí)類型被假定為Object。  | 
|   nullValue  |   nullValue可以設(shè)置為任何的有效值(這取決于property的類型)。 注意:對(duì)于值類型(int,double,datetime等)的屬性,它們是不能為null的,那如何向數(shù)據(jù)庫中插入null值呢?可以采用nullValue,比如對(duì)于Age列(int類型),我們可以指定nullValue為0,這意味著如果該屬性未設(shè)置(C#中,int屬性的默認(rèn)值為0),那么會(huì)向數(shù)據(jù)庫插入NULL。在.NET2.0中也可以使用nullable類型,此時(shí)更為方便。請(qǐng)參考我的小文。  | 
|   size  |   設(shè)置列的最大尺寸。  | 
|   precision  |   設(shè)置數(shù)字值的精度。  | 
|   scale  |   設(shè)置小數(shù)的位數(shù)。  | 
|   typeHandler  |   用于自定義類型處理器(Custom Type Handler)。  | 
內(nèi)聯(lián)參數(shù)在多數(shù)情況下效果不錯(cuò)。如果您希望改善性能,或者遇到了意外的情況,外部參數(shù)可能就用得上了。在第5章中,我們會(huì)更全面地討論外部參數(shù),在這里,暫不需要。
4.3.2?重溫內(nèi)聯(lián)參數(shù)
如果您更喜歡使用內(nèi)聯(lián)參數(shù),同樣可以為參數(shù)指定更多的信息,如屬性的類型,類的類型以及null值替換(即nullValue特性)。看下面四個(gè)例子:
<statement?id="insertProduct"?parameterClass="Product">????insert?into?PRODUCT?(PRD_ID,?PRD_DESCRIPTION)
????values?(#id#,?#description#)
</statement>
這是最簡單的情況,下面這個(gè)例子指定了dbType:
<statement?id="insertProduct"?parameterClass="Product">????insert?into?PRODUCT?(PRD_ID,?PRD_DESCRIPTION)
????values?(#id:int#,?#description:VarChar#)
</statement>
下面這個(gè)例子指定了nullValue:
<statement?id="insertProduct"?parameterClass="Product">????insert?into?PRODUCT?(PRD_ID,?PRD_DESCRIPTION)
????values?(#id:int:-999999#,?#description:VarChar#)
</statement>
類似于Java中的DataMapper,內(nèi)聯(lián)參數(shù)還有另外一種語法,使用逗號(hào)。
<update?id="UpdateAccountViaInlineParameters"?parameterClass="Account">????update?Accounts?set
????Account_FirstName?=?#FirstName#,
????Account_LastName?=?#LastName#,
????Account_Email?=?#EmailAddress,type=string,dbType=Varchar,nullValue=no_email@provided.com#
????where
????Account_ID?=?#Id#
</update>
4.3.3?標(biāo)準(zhǔn)類型的參數(shù)(standard type parameter)
在實(shí)際開發(fā)中,我們會(huì)發(fā)現(xiàn)很多語句只接受單個(gè)參數(shù),通常為int或string。此時(shí)并不需要將其封裝在另一個(gè)對(duì)象中,直接使用標(biāo)準(zhǔn)庫對(duì)象(string, int等)就可以了,下面是一個(gè)例子:?
????select?*?from?PRODUCT?where?PRD_ID?=?#value#
</statement>
假定PRD_ID為數(shù)字類型,在調(diào)用該語句時(shí),可以傳入一個(gè)標(biāo)準(zhǔn)的int對(duì)象。#value#參數(shù)會(huì)替換為傳入的int值。此處的value僅僅是一個(gè)占位符,您可以根據(jù)需要將其替換為其它名稱。
為方便起見,iBATIS框架提供了基元類型的別名,比如,int可用于代替System.Int32。要了解這些別名的完整內(nèi)容,請(qǐng)參考iBATIS.NET的官方文檔。
4.3.4 IDictionary類型的參數(shù)
<statement?id="getProduct"?parameterClass="System.Collections.IDictionary">????select?*?from?PRODUCT
????where?PRD_CAT_ID?=?#catId#
????and?PRD_CODE?=?#code#
</statement>
我們也可以使用IDictionary類型的對(duì)象作為參數(shù)。通常可以使用Hashtable。看下面的例子:
看看這條語句,跟前面出現(xiàn)的沒有什么不同。如果傳入的對(duì)象是Hashtable類型,它必須要包含有名稱為catId和code的鍵,而鍵所對(duì)應(yīng)的值必須要適合于列的類型,這些要求與使用普通的對(duì)象是一樣的。
為方便起見,iBATIS框架也提供了IDictionary類型的別名。因此,可以用map或hashtable來代替System.Collections.Hashtable。要了解這些別名的完整內(nèi)容,請(qǐng)參考iBATIS.NET的官方文檔。
OK,至此我們已經(jīng)知道了如何輸入?yún)?shù)了,下面就來看看如何獲取輸出值了。
4.4結(jié)果映射(result map)
Result Map將從數(shù)據(jù)庫查詢所得的結(jié)果映射到對(duì)象的屬性。在使用映射語句時(shí),Result Map是我們要理解的最常用也是最重要的特性之一。
通過Result Map我們可以控制如何從查詢結(jié)果中獲取數(shù)據(jù),以及列是如何映射到對(duì)象的屬性的。Result Map可以描述列的類型、null值的替換以及復(fù)雜屬性(包括集合)的映射。
4.4.1?擴(kuò)展Result Map
可選的extends特性值可以設(shè)置為另一個(gè)Result Map的名稱,這樣就可以復(fù)用指定Result Map的映射方式了。“父級(jí)”Result Map的所有屬性都將作為當(dāng)前Result Map的一部分,“父級(jí)”Result Map的值在當(dāng)前Result Map之前進(jìn)行設(shè)置,其效果類似于類的繼承。
提示:“父級(jí)”Result Map必須在“子級(jí)”Result Map之前定義。
4.4.2 <resultMap>的特性
<resultMap>接受三個(gè)特性:
|   特性 
  |   描述 
  | 
|   id  |   必需的,為Result Map提供唯一標(biāo)識(shí)。  | 
|   class  |   可選的,指定當(dāng)前Result Map使用的類。可以設(shè)置為類的完整名稱或別名。  | 
|   extends  |   可選的,指定要進(jìn)行“繼承”的Result Map。  | 
4.4.3 <constructor>元素
<constructor>元素必須與result class的構(gòu)造函數(shù)簽名相匹配。如果指定了此元素,iBATIS用它來實(shí)例化結(jié)果對(duì)象(result object)。
4.4.4 <result>元素
<resultMap>元素包含一個(gè)或多個(gè)<result>子元素,用以將執(zhí)行SQL的結(jié)果集映射至對(duì)象的屬性。
|   特性 
  |   描述 
  | 
|   property  |   必需的,表示結(jié)果對(duì)象的屬性名稱。  | 
|   column  |   必需的,指定結(jié)果集中的列名稱,使用該列來產(chǎn)生當(dāng)前屬性。  | 
|   columnIndex  |   可選的,指定列的索引,該特性對(duì)性能會(huì)有輕微的幫助。99%的應(yīng)用程序中是不需要的,而且它還會(huì)犧牲可維護(hù)性和可讀性。另外一些provider中,該特性可能對(duì)性能沒有任何幫助。  | 
|   dbType  |   用于顯式地指定列的類型。由于CLR和數(shù)據(jù)庫中類型的不一致,該特性比較有用,尤其是對(duì)datetime和string類型。  | 
|   type  |   用于顯式地指定結(jié)果對(duì)象屬性的CLR類型。通常屬性的類型可通過反射獲得,但在映射到Hashtable之類的對(duì)象時(shí)就無能為力了。  | 
|   resultMapping  |   該特性的值可以設(shè)置為另一個(gè)Result Map的名稱,借助后者來填充屬性。如果使用的Result Map位于另一個(gè)文件中,則必須要使用它的完全限定名稱(加上命名空間)。  | 
|   nullValue  |   用于指定null值的替代值,該特性可以設(shè)置為任何有效的值(取決于屬性的類型)。如果屬性類型為值類型,則其值不可能為null,如果列的值為null,那么通過該特性可以將屬性設(shè)定為某個(gè)常量值。另一方面,如果屬性可以為null,我們可能想用某個(gè)常量值而不是null來表示它,這個(gè)時(shí)候nullValue特性也是有用的。  | 
|   select  |   用于描述對(duì)象間的關(guān)系,并自動(dòng)加載復(fù)雜類型(即用戶定義類型)。其值必須為另一映射語句的名稱。  | 
|   lazyLoad  |   聯(lián)合使用lazyLoad和select特性,可以指定select特性所指定語句的結(jié)果是否要延遲加載。延遲加載對(duì)IList和IList<>的支持是透明的,對(duì)強(qiáng)類型的集合類的支持則需要Castle.DynamicProxy組件。  | 
|   typeHandler  |   允許使用自定義類型處理器(Custom Type Handler)。這樣就可以擴(kuò)展DataMapper的能力,來處理那些provider特定的類型或者是provider不支持的類型。  | 
代碼示例:nullValue的使用
<resultMap?id="get-product-result"?class="product">????<result?property="id"?column="PRD_ID"/>
????<result?property="description"?column="PRD_DESCRIPTION"/>
????<result?property="subCode"?column="PRD_SUB_CODE"?nullValue="-9999"?/>
</resultMap>
注意:如果PRD_SUB_CODE列的值為null,則subCode屬性的值將設(shè)置為-9999。記住,在插入/更新數(shù)據(jù)時(shí),Parameter Map的nullValue特性也要進(jìn)行設(shè)置,這樣才能一致。實(shí)際上有了nullable類型后,該特性可以不使用了。
4.4.5?隱式的結(jié)果映射
如果SQL語句返回的列與結(jié)果對(duì)象的屬性相匹配,那么顯式的Result Map就不再必要了。在下面的例子中,列的名稱和屬性的名稱已然匹配,因此無需聲明Result Map。
<statement?id="selectProduct"?resultClass="Product">????select
????id,
????description
????from?PRODUCT
????where?id?=?#value#
</statement>
但是,如果列的名稱和屬性名稱不一致,而列名不可能修改(比如使用其它公司開發(fā)的數(shù)據(jù)庫),那該怎么辦呢?可以使用列的別名,看下例:
<statement?id="selectProduct"?resultClass="Product">????select
????PRD_ID?as?id,
????PRD_DESCRIPTION?as?description
????from?PRODUCT
????where?PRD_ID?=?#value#
</statement>
當(dāng)然,此時(shí)就不能指定dbType、nullValue或者其它的特性了(不要太貪心…)。
區(qū)分大小寫是隱式Result Map的另一個(gè)問題。誠然,我們可為一個(gè)類同時(shí)定義“FirstName”和“Firstname”兩個(gè)屬性,在iBATIS進(jìn)行映射時(shí),它就不能保證是匹配哪個(gè)屬性了(當(dāng)然了,沒幾個(gè)開發(fā)人員會(huì)定義這樣相近的兩個(gè)屬性)。
最后,隱式Result Map會(huì)有性能損失,如果我們使用第三方的.NET數(shù)據(jù)庫provider,而它又對(duì)ResultSetMetaData支持很差,那損失就更明顯了。
4.4.6?返回基元類型的結(jié)果(如string,int等)
很多時(shí)候,并不需要返回一個(gè)具有多個(gè)屬性的對(duì)象,我們需要的僅僅是單個(gè)的string,int,bool等類型的值。這時(shí),您可以指定標(biāo)準(zhǔn)類型作為結(jié)果類型,如:
<select?id="selectProductCount"?resultClass="System.Int32">????select?count(*)?from?PRODUCT
</select>
結(jié)果類型也可使用iBATIS框架提供的別名,比如,int可用于代替System.Int32。要了解這些別名的完整內(nèi)容,請(qǐng)參考iBATIS.NET的官方文檔。
4.4.7?返回IDictionary類型的結(jié)果
有些時(shí)候我們需要的只是包含數(shù)據(jù)的鍵/值列表。Result Map可以生成一個(gè)IDictionary類型的實(shí)例,其語法與普通的POCO對(duì)象一樣:
<resultMap?id="select-product-result"?class="hashtable">????<result?property="id"?column="PRD_ID"/>
????<result?property="code"?column="PRD_CODE"/>
????<result?property="description"?column="PRD_DESCRIPTION"/>
????<result?property="suggestedPrice"?column="PRD_SUGGESTED_PRICE"/>
</resultMap>
在這個(gè)例子中,iBATIS會(huì)為每一行創(chuàng)建一個(gè)Hashtable實(shí)例,這個(gè)實(shí)例包含了返回的數(shù)據(jù),屬性名id、code等均作為Hashtable的key,列的值則作為Hashtable的值。
也可以使用IDictionary類型作為隱式的Result Map:
<statement?id="selectProductCount"?resultClass="hashtable">????select?*?from?PRODUCT
</statement>
Hashtable包含的值取決于列的值。如果列發(fā)生了變化(比如添加或刪除了列),返回的結(jié)果也會(huì)隨之發(fā)生變化。
注意:某些provider可能將返回的列名稱定為大寫或小寫,此時(shí)要注意使用正確的key名稱。
4.5?小結(jié)
在本章中,我們探討了POCO,SQL Map的API,映射語句。隨著您對(duì)這些內(nèi)容的熟悉,創(chuàng)建映射語句也會(huì)越來越簡單,就像其它任何事情一樣,熟能生巧。
如果您希望盡可能地減少運(yùn)行時(shí)的錯(cuò)誤,就要顯式聲明!使用顯式的參數(shù)和結(jié)果映射,并且要使用強(qiáng)類型的對(duì)象。這樣,您的程序會(huì)啟動(dòng)更快(因?yàn)閕BATIS會(huì)嘗試推導(dǎo)所有內(nèi)容),運(yùn)行更快,使用的內(nèi)存更少。
在下章中,我們將研究iBATIS支持的非查詢語句,屆時(shí),我們就能夠了解數(shù)據(jù)庫維護(hù)所需的各種基本操作了。
點(diǎn)擊這里下載示例代碼(數(shù)據(jù)庫為Northwind,請(qǐng)修改SqlMap.config中的配置)。
下一篇:iBATIS In Action:執(zhí)行非查詢語句(一);
本文轉(zhuǎn)自一個(gè)程序員的自省博客園博客,原文鏈接:http://www.cnblogs.com/anderslly/archive/2007/11/04/ibatisusingmappedstatement02.html,如需轉(zhuǎn)載請(qǐng)自行聯(lián)系原作者。
總結(jié)
以上是生活随笔為你收集整理的iBATIS In Action:使用映射语句(二)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
                            
                        - 上一篇: Struts2、Spring3、MyBa
 - 下一篇: 七种设计原则(二)单一职责原则