[原]iBatis.Net(C#)系列二:SQL數(shù)據(jù)映射
Posted on 2013-03-01 09:54 北極燕鷗 閱讀(8789) 評(píng)論(5) 收藏 舉報(bào)轉(zhuǎn)載請(qǐng)注明 http://www.rzrgm.cn/13590/archive/2013/03/01/2938126.html
摘要:本文探討了iBatis.Net框架的XML數(shù)據(jù)映射文件各配置節(jié)點(diǎn)的含義,并通過(guò)CRUD四種對(duì)數(shù)據(jù)庫(kù)的操作講解了如何配置數(shù)據(jù)映射文件和調(diào)用方法。
關(guān)鍵詞:iBatis.Net;XML;SQL Maps;數(shù)據(jù)映射
上一節(jié)介紹了iBatis.Net的基本情況和運(yùn)行原理,運(yùn)行環(huán)境中各參數(shù)的配置情況。并通過(guò)一個(gè)實(shí)例項(xiàng)目進(jìn)行了說(shuō)明。
1 數(shù)據(jù)映射基礎(chǔ)
SQL Maps是這個(gè)iBatis.Net框架中最重要的部分,而SQL Maps的核心就在于XML數(shù)據(jù)映射文件(Data Map XML File)。在XML數(shù)據(jù)映射文件里可以定義包括要執(zhí)行各種SQL語(yǔ)句、存儲(chǔ)過(guò)程、輸入?yún)?shù)映射、返回結(jié)果映射、緩存機(jī)制,并且能通過(guò)幾種相對(duì)比較復(fù)雜的配置實(shí)現(xiàn)對(duì)象之間的關(guān)聯(lián)關(guān)系和延遲加載。這也是iBatis.Net區(qū)別其它ORM框架而具備更靈活性,更高性能的關(guān)鍵所在。
配置文件可以寫得很簡(jiǎn)單,也可以很復(fù)雜。復(fù)雜配置文件往往出于更好的設(shè)計(jì),更好性能,更好擴(kuò)展性方面的目的。一個(gè)XML數(shù)據(jù)映射文件主要分為兩個(gè)部分:模塊配置和語(yǔ)句配置。
2 模塊配置
2.1 Type Alias節(jié)點(diǎn)
定義一個(gè)XML數(shù)據(jù)映射文件中的別名,其好處就是避免過(guò)長(zhǎng)變量值的反復(fù)書寫,比如通過(guò)typeAlias節(jié)點(diǎn)為類"iBatisTest.Domain.Sysuser"定義了一個(gè)別名"Sysuser",這樣在這個(gè)數(shù)據(jù)映射文件中的其他部分,需要引用"iBatisTest.Domain.Sysuser"類時(shí),只需以其別名替代即可,和SqlMap.config配置文件里面的Alias節(jié)點(diǎn)配置一樣。定義如:
<alias><typeAlias alias="Sysuser" type="iBatisTest.Domain.Sysuser,iBatisTest" /></alias>
2.2 cacheModel節(jié)點(diǎn)
緩存機(jī)制是程序開發(fā)中經(jīng)常討論的一個(gè)話題,在實(shí)際的系統(tǒng)開發(fā)的過(guò)程中,總會(huì)存在著這樣一類數(shù)據(jù),它們更新頻率很低,然而使用的頻率卻非常之高。為了提高系統(tǒng)性能,通常將此類數(shù)據(jù)裝入緩存。iBatis.Net也有自己的緩存系機(jī)制,它通過(guò)cacheModel節(jié)點(diǎn)來(lái)配置,具體的定義如下:
<cacheModel type="LRU" id="Sysuser-cache" readOnly="true" serialize="false">
<flushInterval hours="24"/>
<flushOnExecute statement="SysuserMap. UpdateSysuser "/>
<property name="CacheSize" value="100"/>
</cacheModel>
type:緩存的類型,iBatis.Net中有4種類型,分別為MEMORY、LRU、FIFO、OSCACHE。
其中MEMORY是內(nèi)存緩存,LRU是使用最近最少使用策略,F(xiàn)IFO是使用先進(jìn)先出策略,OSCACHE是通過(guò)第三方的緩存插件來(lái)實(shí)現(xiàn)。
id:是cacheModel的一個(gè)標(biāo)識(shí),標(biāo)識(shí)該緩存的名字,供后面設(shè)置使用。
readOnly:指緩存的數(shù)據(jù)對(duì)象是只讀還是可讀寫,默認(rèn)為"true",即只讀,這里的只讀并不是意味著數(shù)據(jù)對(duì)象一旦放入緩存中就無(wú)法再對(duì)數(shù)據(jù)進(jìn)行修改。而是當(dāng)數(shù)據(jù)對(duì)象發(fā)生變化的時(shí)候,如數(shù)據(jù)對(duì)象的某個(gè)屬性發(fā)生了變化,則此數(shù)據(jù)對(duì)象就將被從緩存中廢除,下次需要需重新從數(shù)據(jù)庫(kù)讀取數(shù)據(jù),構(gòu)造新的數(shù)據(jù)對(duì)象。而readOnly="false"則意味著緩存中的數(shù)據(jù)對(duì)象可更新。
serialize:是否從緩存中讀取同一個(gè)對(duì)象,還是對(duì)象的副本。該參數(shù)只有在readOnly為false的情況下才有效, 因?yàn)榫彺媸侵蛔x的,那么為不同會(huì)話返回的對(duì)象肯定是一個(gè),只有在緩存是可讀寫的時(shí)候,才需要為每個(gè)會(huì)話返回對(duì)象的副本。
flushInterval:指定緩存自動(dòng)刷新的時(shí)間,可以為hours、minutes、seconds和milliseconds。需要注意的是,這個(gè)間隔時(shí)間不是時(shí)間到了,在緩存里的信息會(huì)自動(dòng)刷新,而是在間隔時(shí)間過(guò)后,下次查詢將不會(huì)從緩存中去取值,而會(huì)用SQL去查詢,同時(shí)將查詢的結(jié)果更新緩存的值。
flushOnExecute:指定在發(fā)生哪些操作時(shí),更新緩存。
property:針對(duì)cacheModel的額外的一些屬性配置,不同type的cacheModel將會(huì)有自己專有的一些property配置,如:
FIFO: <property name="CacheSize" value="100" />
LRU: <property name="CacheSize" value="100" />
MEMORY: <property name="Type" value="WEAK" />
當(dāng)配置好cacheModel之后就可以在后面的語(yǔ)句中使用了,如:
﹤statement id="SelectSysuser" resultClass="Sysuser" cacheModel="Sysuser-cache"﹥
SELECT * FROM DEAN.SYSUSER
﹤/statement﹥
2.3 resultMap節(jié)點(diǎn)
resultMap從字面理解就是結(jié)果集的映射,它將返回的記錄與實(shí)體對(duì)象進(jìn)行映射,它屬于直接映射。如果查詢出來(lái)的數(shù)據(jù)集的字段與屬性和實(shí)體類一致時(shí),我們常用resultClass來(lái)替代,它屬于隱身映射。通常resultMap比resultClass性能要高。
在使用resultMap時(shí)需要注意,如果在resultMap中給出的配置字段,但是返回的數(shù)據(jù)集卻沒有返回這個(gè)字段,那程序?qū)⒊鰭伋霎惓!O喾吹模绻祷亓艘恍┳侄危瑓s沒有在resultMap給出配置定義的話,那么那些字段將不會(huì)被處理而不會(huì)給出任何的提示,相當(dāng)沒有查詢出這些字段。具體的定義例子如下:
<resultMaps>
<resultMap id="SysuserResult" class="Sysuser">
<result property="Userid" column="USERID" />
<result property="Password" column="PASSWORD" />
<result property="Loginname" column="LOGINNAME" />
<result property="Sex" column="SEX"/>
<result property="Birthday" column="BIRTHDAY"/>
<result property="Idcard" column="IDCARD" />
<result property="Officephone" column="OFFICEPHONE" />
<result property="Familyphone" column="FAMILYPHONE" />
<result property="Mobilephone" column="MOBILEPHONE"/>
<result property="Email" column="EMAIL"/>
<result property="Address" column="ADDRESS"/>
<result property="Zipcode" column="ZIPCODE"/>
<result property="Remark" column="REMARK" />
<result property="Status" column="STATUS" />
<result property="Registerdate" column="REGISTERDATE" />
</resultMap>
</resultMaps>
該參數(shù)也是查詢語(yǔ)句特有的配置項(xiàng),因?yàn)?span style="font-family: Arial">insert,update,delete三種語(yǔ)句的操作是不會(huì)返回?cái)?shù)據(jù)結(jié)果集的,也就沒有resultMap和resultClass。如果在一個(gè)語(yǔ)句配置中同時(shí)指定了resultMap和resultClass屬性的話,將會(huì)優(yōu)先使用resultMap。同時(shí)result Map的使用也是一個(gè)實(shí)現(xiàn)對(duì)象復(fù)雜查詢功能的重要手段,如:result map的繼承,對(duì)象的1..1、1..N關(guān)系查詢。
2.4 ParameterMap節(jié)點(diǎn)
參數(shù)映射的配置,它是被用來(lái)向一個(gè)語(yǔ)句提供所需參數(shù)的配置。該參數(shù)配置節(jié)點(diǎn)和resultMaps節(jié)點(diǎn)類似。
3 語(yǔ)句配置
語(yǔ)句配置(Mapped Statements):顧名思義就是映射的語(yǔ)句聲明。它是XML數(shù)據(jù)映射文件的核心,在iBatis.Net框架中真正和數(shù)據(jù)庫(kù)打交道的被執(zhí)行的SQL語(yǔ)句(或存儲(chǔ)過(guò)程)都必須在這里被顯式聲明。語(yǔ)句配置可以包含有:statement、select、insert、update、delete和procedure這6種不同的語(yǔ)句類型。其中statement可以包含所有類型的SQL語(yǔ)句(存儲(chǔ)過(guò)程),它是一個(gè)泛泛的語(yǔ)句配置,沒特別明確的職責(zé),相反,其它5種類型的語(yǔ)句配置就是專門負(fù)責(zé)各種不同的SQL語(yǔ)句。下面這張表列出了各種類型的語(yǔ)句的不同職責(zé)和調(diào)用方法。
|
Statement類型 |
屬性 |
子元素 |
方法 |
|
<statement> |
id parameterClass resultClass parameterMap resultMap cacheModel |
所有動(dòng)態(tài)元素 |
update delete 所有的查詢方法 |
|
<insert> |
id parameterClass parameterMap |
所有的動(dòng)態(tài)元素 <selectKey> |
insert update delete |
|
<update> |
id parameterClass parameterMap |
所有的動(dòng)態(tài)元素 |
insert update delete |
|
<delete> |
id parameterClass parameterMap |
所有的動(dòng)態(tài)元素 |
insert update delete |
|
<select> |
id parameterClass resultClass parameterMap resultMap cacheModel |
所有的動(dòng)態(tài)元素 |
所有的查詢方法 |
|
<procedure> |
id parameterClass resultClass parameterMap resultMap |
所有的動(dòng)態(tài)元素 |
insert update delete 所有的查詢方法 |
應(yīng)用系統(tǒng)操作數(shù)據(jù)庫(kù)數(shù)據(jù)一般有CRUD四種方式,即增加(Create)、查詢(Retrieve,重新得到數(shù)據(jù))、更新(Update)和刪除(Delete)。下面詳細(xì)介紹一下這四種情況的SQL語(yǔ)句配置及調(diào)用方法。
首先在Oracle數(shù)據(jù)庫(kù)中新建表DEAN.SYSUSER。表結(jié)構(gòu)如圖1

圖1:SYSUSER表結(jié)構(gòu)
增加實(shí)體類iBatisTest.Domain.Sysuser,該實(shí)體類和表DEAN.SYSUSER對(duì)應(yīng)。Sysuser類代碼如下:
using System;
namespace iBatisTest.Domain
{
[Serializable]
public sealed class Sysuser
{
#region 私有成員定義
private Int32 _userid;
private string _password;
private string _loginname;
private string _sex;
private DateTime _birthday;
private string _idcard;
private string _officephone;
private string _familyphone;
private string _mobilephone;
private string _email;
private string _address;
private string _zipcode;
private string _remark;
private string _status;
private DateTime _registerdate;
#endregion 私有成員定義
#region 定義默認(rèn)類結(jié)構(gòu)函數(shù)
public Sysuser()
{
_userid = 0;
_password = null;
_loginname = null;
_sex = null;
_birthday = new DateTime();
_idcard = null;
_officephone = null;
_familyphone = null;
_mobilephone = null;
_email = null;
_address = null;
_zipcode = null;
_remark = null;
_status = null;
_registerdate = new DateTime();
}
#endregion 定義默認(rèn)類結(jié)構(gòu)函數(shù)
#region 定義公有屬性
/// <summary>
/// 登錄ID
/// </summary>
public Int32 Userid
{
get { return _userid; }
set { _userid = value; }
}
/// <summary>
/// 登錄密碼
/// </summary>
public string Password
{
get { return _password; }
set
{
if( value!= null && value.Length > 40)
throw new ArgumentOutOfRangeException("密碼值錯(cuò)誤", value, value.ToString());
_password = value;
}
}
/// <summary>
/// 登錄用戶名
/// </summary>
public string Loginname
{
get { return _loginname; }
set
{
if( value!= null && value.Length > 40)
throw new ArgumentOutOfRangeException("登錄用戶名值錯(cuò)誤", value, value.ToString());
_loginname = value;
}
}
/// <summary>
/// 性別
/// </summary>
public string Sex
{
get { return _sex; }
set
{
if( value!= null && value.Length > 40)
throw new ArgumentOutOfRangeException("性別值錯(cuò)誤", value, value.ToString());
_sex = value;
}
}
/// <summary>
/// 出生日期
/// </summary>
public DateTime Birthday
{
get { return _birthday; }
set { _birthday = value; }
}
/// <summary>
/// 身份證號(hào)
/// </summary>
public string Idcard
{
get { return _idcard; }
set
{
if( value!= null && value.Length > 18)
throw new ArgumentOutOfRangeException("身份證號(hào)值錯(cuò)誤", value, value.ToString());
_idcard = value;
}
}
/// <summary>
/// 辦公電話
/// </summary>
public string Officephone
{
get { return _officephone; }
set
{
if( value!= null && value.Length > 40)
throw new ArgumentOutOfRangeException("辦公電話值錯(cuò)誤", value, value.ToString());
_officephone = value;
}
}
/// <summary>
/// 家庭電話
/// </summary>
public string Familyphone
{
get { return _familyphone; }
set
{
if( value!= null && value.Length > 40)
throw new ArgumentOutOfRangeException("家庭電話值錯(cuò)誤", value, value.ToString());
_familyphone = value;
}
}
/// <summary>
/// 手機(jī)
/// </summary>
public string Mobilephone
{
get { return _mobilephone; }
set
{
if( value!= null && value.Length > 40)
throw new ArgumentOutOfRangeException("手機(jī)號(hào)值錯(cuò)誤", value, value.ToString());
_mobilephone = value;
}
}
/// <summary>
/// </summary>
public string Email
{
get { return _email; }
set
{
if( value!= null && value.Length > 100)
throw new ArgumentOutOfRangeException("Email值錯(cuò)誤", value, value.ToString());
_email = value;
}
}
/// <summary>
/// 通訊地址
/// </summary>
public string Address
{
get { return _address; }
set
{
if( value!= null && value.Length > 200)
throw new ArgumentOutOfRangeException("通訊地址值錯(cuò)誤", value, value.ToString());
_address = value;
}
}
/// <summary>
/// 郵編
/// </summary>
public string Zipcode
{
get { return _zipcode; }
set
{
if( value!= null && value.Length > 20)
throw new ArgumentOutOfRangeException("郵編值錯(cuò)誤", value, value.ToString());
_zipcode = value;
}
}
/// <summary>
/// 備注
/// </summary>
public string Remark
{
get { return _remark; }
set
{
if( value!= null && value.Length > 200)
throw new ArgumentOutOfRangeException("備注值錯(cuò)誤", value, value.ToString());
_remark = value;
}
}
/// <summary>
/// 狀態(tài)
/// </summary>
public string Status
{
get { return _status; }
set
{
if( value!= null && value.Length > 20)
throw new ArgumentOutOfRangeException("狀態(tài)值錯(cuò)誤", value, value.ToString());
_status = value;
}
}
/// <summary>
/// 注冊(cè)時(shí)間
/// </summary>
public DateTime Registerdate
{
get { return _registerdate; }
set {_registerdate = value; }
}
#endregion 定義公有屬性
}
}
(1)添加
添加也即插入,使用的SQL語(yǔ)句是insert。XML數(shù)據(jù)映射配置信息如下:
<insert id="InsertSysuser" parameterClass="Sysuser">
INSERT INTO DEAN.SYSUSER
(USERID,PASSWORD,LOGINNAME,SEX,BIRTHDAY,IDCARD,OFFICEPHONE,FAMILYPHONE,MOBILEPHONE,EMAIL,ADDRESS,ZIPCODE,REMARK,STATUS)
VALUES (#Userid#,#Password#,#Loginname#,#Sex#,#Birthday#,#Idcard#,#Officephone#,#Familyphone#,#Mobilephone#,#Email#,#Address#,#Zipcode#,#Remark#,#Status#)
</insert>
insert標(biāo)簽表面該語(yǔ)句是插入語(yǔ)句,id為該配置語(yǔ)句的標(biāo)識(shí),在后面的調(diào)用中通過(guò)該標(biāo)識(shí)引用這個(gè)語(yǔ)句。變量用#號(hào)分隔,如"#Userid#"在運(yùn)行期會(huì)由傳入的Sysuser對(duì)象的Userid屬性填充,注意變量名需區(qū)分大小寫。調(diào)用代碼如下:
protected void BtnAddUser_Click(object sender, EventArgs e)
{
try
{
iBatisTest.Domain.Sysuser model = new iBatisTest.Domain.Sysuser();//實(shí)例化Sysuser對(duì)象
model.Userid = 1;//Userid為主鍵,多次添加需修改該值
model.Password = "123";
model.Loginname ="dean";
model.Sex = "男";
model.Birthday = Convert.ToDateTime("1980-01-01");
model.Idcard ="510200198001014200";
model.Officephone="86279528";
model.Familyphone ="86279528";
model.Mobilephone = "13880980000";
model.Email ="476408321@qq.com";
model.Address = "四川成都";
model.Zipcode = null;
model.Remark = null;
model.Status = "有效";
ISqlMapper mapper = Mapper.Instance(); //得到ISqlMapper實(shí)例
mapper.Insert("SysuserMap.InsertSysuser", model);//調(diào)用Insert方法
Label1.Text = "添加用戶成功";
}
catch (Exception ex)
{
Label1.Text = ex.Message;
}
}
調(diào)用程序先實(shí)例化Sysuser對(duì)象并賦值,再得到ISqlMapper的實(shí)例,調(diào)用該實(shí)例的Insert方法。Insert方法有兩個(gè)參數(shù),分別是語(yǔ)句名稱和參數(shù)對(duì)象。語(yǔ)句名稱就是數(shù)據(jù)映射文件里面的配置語(yǔ)句id,參數(shù)對(duì)象是一個(gè)object對(duì)象,可以傳入類、單個(gè)值或者哈希表等。
編譯程序,點(diǎn)擊"添加用戶"按鈕運(yùn)行調(diào)用程序,系統(tǒng)會(huì)成功的向數(shù)據(jù)庫(kù)SYSUSER表新增一條記錄。查詢數(shù)據(jù)庫(kù)結(jié)果如圖2所示:

圖2:新增數(shù)據(jù)后數(shù)據(jù)庫(kù)結(jié)果
(2)更新
更新修改操作使用的SQL語(yǔ)句為update,XML數(shù)據(jù)映射文件配置信息為:
<update id="UpdateSysuser" parameterClass="Sysuser">
UPDATE SYSUSER
SET PASSWORD=#Password#,LOGINNAME=#Loginname#,SEX=#Sex#,BIRTHDAY=#Birthday#,IDCARD=#Idcard#,OFFICEPHONE=#Officephone#,FAMILYPHONE=#Familyphone#,MOBILEPHONE=#Mobilephone#,EMAIL=#Email#,ADDRESS=#Address#,ZIPCODE=#Zipcode#,REMARK=#Remark#,STATUS=#Status#
WHERE USERID = #Userid#
</update>
調(diào)用代碼為:
protected void BtnUpdateUser_Click(object sender, EventArgs e)
{
try
{
iBatisTest.Domain.Sysuser model = new iBatisTest.Domain.Sysuser();
model.Userid = 1;//修改Userid為1的用戶信息
model.Password = "1234";
model.Loginname = "deanu";
model.Sex = "男";
model.Birthday = Convert.ToDateTime("1970-01-01");
model.Idcard = "310200198001014200";
model.Officephone = "76279528";
model.Familyphone = "76279528";
model.Mobilephone = "13880000000";
model.Email = "1@qq.com";
model.Address = null;
model.Zipcode = "610000";
model.Remark = "修改ID為1的用戶";
model.Status = "有效";
ISqlMapper mapper = Mapper.Instance(); //得到ISqlMapper實(shí)例
mapper.Update("SysuserMap.UpdateSysuser", model);//調(diào)用Update方法
Label1.Text = "修改用戶成功";
}
catch (Exception ex)
{
Label1.Text = ex.Message;
}
}
(3)刪除
刪除操作使用的SQL語(yǔ)句為delete,XML數(shù)據(jù)映射文件配置信息為:
<delete id="DeleteSysuser" parameterClass="int">
DELETE FROM SYSUSER WHERE USERID = #Userid#
</delete>
由于刪除操作是根據(jù)主鍵進(jìn)行處理的,傳入?yún)?shù)為整形值,因此在parameterClass直接為int。調(diào)用代碼為:
protected void BtnDelete_Click(object sender, EventArgs e)
{
//刪除用戶
try
{
ISqlMapper mapper = Mapper.Instance(); //得到ISqlMapper實(shí)例
mapper.Delete("SysuserMap.DeleteSysuser", 1);//調(diào)用Delete方法
Label1.Text = "刪除用戶成功";
}
catch (Exception ex)
{
Label1.Text = ex.Message;
}
}
(4)查詢
查詢操作使用的語(yǔ)句為select語(yǔ)句,XML數(shù)據(jù)映射文件配置信息為:
<select id="SelectSysuser" parameterClass="int" resultMap="SysuserResult">
SELECT USERID,PASSWORD,LOGINNAME,SEX,BIRTHDAY,IDCARD,OFFICEPHONE,FAMILYPHONE,MOBILEPHONE,EMAIL,ADDRESS,ZIPCODE,REMARK,STATUS,REGISTERDATE
FROM SYSUSER WHERE USERID = #Userid#
</select>
調(diào)用代碼為:
protected void BtnQuery_Click(object sender, EventArgs e)
{
//查詢用戶
try
{
ISqlMapper mapper = Mapper.Instance(); //得到ISqlMapper實(shí)例
int Userid = 1;
IList<iBatisTest.Domain.Sysuser> plist = mapper.QueryForList<iBatisTest.Domain.Sysuser>("SysuserMap.SelectSysuser", Userid);//調(diào)用QueryForList方法
if (plist != null && plist.Count > 0)
{
gvUserData.DataSource = plist;
gvUserData.DataBind();
}
Label1.Text = "查詢用戶成功";
}
catch (Exception ex)
{
Label1.Text = ex.Message;
}
}
調(diào)用ISqlMapper實(shí)例的QueryForList方法返回的是一個(gè)IList泛型接口,這里指定為iBatisTest.Domain.Sysuser對(duì)象。程序運(yùn)行結(jié)果如圖3所示。

圖3:查詢結(jié)果
以上4種配置語(yǔ)句都可以用statement來(lái)代替,其配置信息和調(diào)用代碼完全一樣。但用statement定義所有操作,缺乏直觀性。建議在開發(fā)中根據(jù)實(shí)際情況來(lái)選用配置,既使得配置文件直觀,又可以借助xsd對(duì)節(jié)點(diǎn)聲明進(jìn)行更有針對(duì)性的檢查,以避免配置上的失誤。
4 特殊配置
4.1 XML轉(zhuǎn)義字符
很多時(shí)候在SQL語(yǔ)句中會(huì)用到大于或者下于符號(hào)(即:><),這個(gè)時(shí)候就與XML規(guī)范相沖突,影響XML映射文件的合法性。通過(guò)加入CDATA節(jié)點(diǎn)來(lái)避免這種情況的發(fā)生,如:
<statement id="SelectPersonsByAge" parameterClass="int" resultClass="Person">
<![CDATA[
SELECT * FROM PERSON WHERE AGE > #value#
]]>
</statement>
4.2自動(dòng)生成主鍵
目前很多數(shù)據(jù)庫(kù)都支持為新插入的記錄自動(dòng)生成主鍵,Oracle也提供這種功能,通過(guò)序列加觸發(fā)器來(lái)解決。這當(dāng)然很方便,但是當(dāng)希望在插入一條記錄后立即獲得該記錄的主鍵值,問(wèn)題就出現(xiàn)了,因?yàn)楹芸赡転榇瞬坏貌恍聦懸粭l語(yǔ)句去獲取該主鍵值。iBatis.Net提供了一種比較好的解決方式。通過(guò)在XML數(shù)據(jù)映射文件中的<selectKey>元素來(lái)獲取這些自動(dòng)生成的主鍵值并將其保存在對(duì)象中。
如上面的"添加"操作配置信息修改為:
<insert id="InsertSysuser" parameterClass="Sysuser">
<selectKey resultClass="int32" property="Userid" type="pre">
SELECT DEAN.SEQ_SYSUSER_USERID.NEXTVAL AS Userid FROM DUAL
</selectKey>
INSERT INTO DEAN.SYSUSER (USERID,PASSWORD,LOGINNAME,SEX,BIRTHDAY,IDCARD,OFFICEPHONE,FAMILYPHONE,MOBILEPHONE,EMAIL,ADDRESS,ZIPCODE,REMARK,STATUS)
VALUES (#Userid#,#Password#,#Loginname#,#Sex#,#Birthday#,#Idcard#,#Officephone#,#Familyphone#,#Mobilephone#,#Email#,#Address#,#Zipcode#,#Remark#,#Status#)
</insert>
粗體部分為新加的selectKey節(jié)點(diǎn)。#Userid#參數(shù)將使用節(jié)點(diǎn)中從序列里選出的值進(jìn)行填充。修改調(diào)用的代碼:
ISqlMapper mapper = Mapper.Instance(); //得到ISqlMapper實(shí)例
Int32 result = (Int32)mapper.Insert("SysuserMap.InsertSysuser", model);//調(diào)用Insert方法
Label1.Text = "添加用戶成功,result返回UserID為" + Convert.ToString(result) + ",Sysuser實(shí)例model的UserID為" + Convert.ToString(model.Userid);
運(yùn)行程序,這樣result就得到想要獲取的鍵值,同時(shí)Sysuser的實(shí)例化對(duì)象model的UserID屬性也返回了該條新記錄的鍵值。
4.3 #與$的選擇
在XML數(shù)據(jù)映射文件中,參數(shù)用#號(hào)來(lái)表示。如前面提到的#Userid#,同時(shí)也可以使用$來(lái)標(biāo)識(shí)。兩者有什么區(qū)別,以及如何選擇呢?
(1)#是把傳入的數(shù)據(jù)當(dāng)作參數(shù),如 order by #field# ,如果#field#傳入的值是字符型,傳入值為id, 則sql語(yǔ)句會(huì)生成order by "id",很明顯生成的sql語(yǔ)句提交給數(shù)據(jù)庫(kù)執(zhí)行會(huì)報(bào)錯(cuò)。#參數(shù)往往用在需傳入實(shí)際變量值的情況,如where id=#id#,變量#id#傳入10,則sql語(yǔ)句會(huì)生成where id=10。
(2)$采用拼接方式生成sql語(yǔ)句,即傳入的數(shù)據(jù)直接生成在sql語(yǔ)句里,如 order by $field$,如$field$傳入的是id,則sql語(yǔ)句會(huì)生成order by id。$參數(shù)方式一般用于傳入數(shù)據(jù)庫(kù)對(duì)象。例如傳入表名。不過(guò)要特別提醒,因?yàn)槭褂迷搮?shù)是直接組成sql語(yǔ)句,所以需注意防止sql注入。
4.4 LIKE語(yǔ)句處理
在查詢處理過(guò)程中,模糊查詢經(jīng)常會(huì)用到。iBatis如何處理這種模糊查詢呢?處理Like模糊查詢iBatis提供以下兩種方法:
(1)使用#參數(shù): 配置如Where UserName Like #param#||'%', 采用參數(shù)傳遞的方式,如#param#傳入字符d,生成的sql語(yǔ)句為Where UserName Like 'd%',其他模糊情況同理可以相應(yīng)配置出來(lái)。
(2)使用$參數(shù):配置如Where UserName Like '$param$%' ,采用字符串替換,就是用參數(shù)的值替換param,如$param$傳入字符d,也可以生成相同的語(yǔ)句。
$方式會(huì)引起sql注入風(fēng)險(xiǎn),實(shí)際的使用中,建議大家都使用第一種配置方式來(lái)處理LIKE模糊查詢。
5 結(jié)語(yǔ)
以上程序在Windows7(64位)+VS2012+Oracle 11g(64位)上測(cè)試通過(guò)。
浙公網(wǎng)安備 33010602011771號(hào)