你可以處理select、update、insert、delete和filter的事件,以驗(yàn)證并處理傳遞給這些操作的參數(shù)值。為了達(dá)到這個(gè)目標(biāo),數(shù)據(jù)綁定的控件和數(shù)據(jù)源控件都暴露了適當(dāng)?shù)氖录@纾趃ridview的updating事件中,你就可以看到keys、newvalues和oldvalues字典中的參數(shù)名稱和值,而它們將會(huì)被傳遞到數(shù)據(jù)源。在數(shù)據(jù)源一端,你可以處理sqldatasource的updating事件,看到這些應(yīng)用到下層命令對(duì)象的參數(shù),而這些命令將會(huì)執(zhí)行以完成相關(guān)操作。類似的,你可以處理objectdatasource的updating事件來查看或改變參數(shù)字典,而這些字典將用于分析updatemethod的適當(dāng)操作。你可以使用這些事件來增加或刪除字典或命令的參數(shù)、改變它們的值、或者簡(jiǎn)單地驗(yàn)證參數(shù)的輸入格式是否正確。
請(qǐng)注意:你尤其需要驗(yàn)證filtering事件的參數(shù)輸入,因?yàn)樵谒鼞?yīng)用到相關(guān)的dataview對(duì)象的filterexpression(過濾器表達(dá)式)之前不會(huì)獲得sql編碼(encoded)。
下面的示例演示了處理多個(gè)數(shù)據(jù)控件的事件來枚舉那些通過事件參數(shù)傳遞的參數(shù)集合。請(qǐng)注意,這個(gè)示例把與orderid主鍵字段相關(guān)聯(lián)的綁定字段的insertvisible屬性設(shè)置為假,這是因?yàn)樵谙聦訑?shù)據(jù)庫中orderid是一個(gè)標(biāo)識(shí)列,不應(yīng)該傳遞給insert操作(當(dāng)插入發(fā)生的時(shí)候數(shù)據(jù)庫自動(dòng)地增加這個(gè)值)。同時(shí)請(qǐng)注意,在datakeynames中,orderid字段被標(biāo)記為主鍵,因此這個(gè)字段的原始值保留在數(shù)據(jù)綁定控件所傳遞的keys字典中。用戶輸入控件的值都傳遞進(jìn)newvalues字典(除了那些標(biāo)記了readonly=false的字段)。非鍵字段的原始值由數(shù)據(jù)綁定控件保留在oldvalues字典中,以供傳遞給數(shù)據(jù)源。這些參數(shù)值都被sqldatasource按照newvalues、keys和oldvalues的次序附加到命令上,盡管在默認(rèn)情況下,當(dāng)conflictdetection被設(shè)置為overwritechanges的時(shí)候,數(shù)據(jù)源不會(huì)附加oldvalues。你可以在后面的"使用沖突檢測(cè)"部分看到數(shù)據(jù)源是如何使用oldvalues的。
<script runat="server">
protected sub enumeratedictionary(byval dictionary as system.collections.specialized.iordereddictionary)
dim entry as dictionaryentry
for each entry in dictionary
response.write(" <b>" & server.htmlencode(entry.key) & "</b>=" & server.htmlencode(entry.value) & " (" & server.htmlencode(entry.value.gettype().name) & ")<br />")
next
end sub
protected sub enumeratecommandparameters(byval command as system.data.common.dbcommand)
response.write("<br/>parameter order in data source...<br />")
dim param as system.data.common.dbparameter
for each param in command.parameters
response.write(" <b>" & server.htmlencode(param.parametername) & "</b>=" & server.htmlencode(param.value) & " (" & server.htmlencode(param.value.gettype().name) & ")<br />")
next
end sub
protected sub detailsview1_itemupdating(byval sender as object, byval e as system.web.ui.webcontrols.detailsviewupdateeventargs)
response.write("<br/>new values passed from detailsview...<br />")
enumeratedictionary(e.newvalues)
response.write("<br/>keys passed from detailsview...<br />")
enumeratedictionary(e.keys)
response.write("<br/>old values passed from detailsview...<br />")
enumeratedictionary(e.oldvalues)
end sub
protected sub sqldatasource1_updating(byval sender as object, byval e as system.web.ui.webcontrols.sqldatasourcecommandeventargs)
enumeratecommandparameters(e.command)
e.cancel = true
response.write("<br/>update canceled")
end sub
你可以通過向數(shù)據(jù)源使用的參數(shù)集合添加靜態(tài)的parameter對(duì)象來改變sqldatasource附加到命令上的參數(shù)次序。sqldatasource會(huì)根據(jù)這些參數(shù)對(duì)象的次序來重新排列數(shù)據(jù)綁定控件所傳遞的參數(shù)。當(dāng)數(shù)據(jù)源的providername屬性被設(shè)置為system.data.oledb的時(shí)候,這種操作就有用處了,這是由于它不支持命名(named)參數(shù),因此附加到命令上的參數(shù)的次序必須與命令中的匿名參數(shù)占位符('?')的次序相匹配。當(dāng)我們使用命名參數(shù)的時(shí)候,參數(shù)的次序就是無關(guān)緊要的。你可以指定parameter對(duì)象的type屬性,確保在執(zhí)行命令或方法之前,強(qiáng)制數(shù)據(jù)綁定控件傳遞的值被轉(zhuǎn)換為適當(dāng)?shù)臄?shù)據(jù)類型。同樣地,你還可以設(shè)置parameter的size屬性,規(guī)定sqldatasource命令中dbparameter的位數(shù)大小(必須用于輸入/輸出、輸出和返回值參數(shù))。
<asp:sqldatasource connectionstring="<%$ connectionstrings:northwindoledb %>" id="sqldatasource1" providername="<%$ connectionstrings:northwindoledb.providername %>" runat="server" selectcommand="select top 10 [orderid], [orderdate], [shipcountry] from [orders]" updatecommand="update [orders] set [orderdate] = ?, [shipcountry] = ? where [orderid] = ?" onupdating="sqldatasource1_updating">
<updateparameters>
<asp:parameter name="orderdate" type="datetime" />
<asp:parameter name="shipcountry" type="string" />
<asp:parameter name="orderid" type="int32" />
</updateparameters>
</asp:sqldatasource>
參數(shù)命名習(xí)慣要求新值根據(jù)數(shù)據(jù)源select操作所選定的字段來命名。我們也可以通過指定oldvaluesparameterformatstring屬性(例如指定為"original_{0}")對(duì)keys或oldvalues中的參數(shù)進(jìn)行重命名,以便于把它們和newvalues參數(shù)區(qū)分開來。你還可以通過處理適當(dāng)?shù)氖录跀?shù)據(jù)源操作執(zhí)行之前改變參數(shù)的值,從而自定義參數(shù)名稱。例如,如果sqldatasource的更新操作與一個(gè)存儲(chǔ)過程關(guān)聯(lián),而該存儲(chǔ)過程使用的參數(shù)名稱與默認(rèn)的命名習(xí)慣不同,那么你就可以在該存儲(chǔ)過程被調(diào)用之前,在sqldatasource的updating事件修改參數(shù)名稱。下面的例子演示了這種技術(shù)。
protected sub sqldatasource1_updating(byval sender as object, byval e as system.web.ui.webcontrols.sqldatasourcecommandeventargs)
e.command.parameters("@id").value = e.command.parameters("@contactid").value
e.command.parameters("@name").value = e.command.parameters("@contactname").value
e.command.parameters.remove(e.command.parameters("@contactid"))
e.command.parameters.remove(e.command.parameters("@contactname"))
end sub
<asp:sqldatasource connectionstring="<%$ connectionstrings:contacts %>" id="sqldatasource1" runat="server" selectcommand="select [contactid], [contactname] from [contacts]" updatecommand="updatecontactname" updatecommandtype="storedprocedure" onupdating="sqldatasource1_updating">
<updateparameters>
<asp:parameter name="id" type="int32" />
<asp:parameter name="name" type="string" />
</updateparameters>
</asp:sqldatasource>
objectdatasource不依賴特定的參數(shù)次序,而是簡(jiǎn)單地查找與參數(shù)名稱相匹配的方法。請(qǐng)注意,objectdatasource不使用參數(shù)的類型或大小來分析方法重載,它僅僅匹配參數(shù)名稱,因此,如果你的業(yè)務(wù)對(duì)象中的兩個(gè)方法擁有相同的名稱和參數(shù)名稱,但是參數(shù)類型不同,objectdatasource是無法把它們區(qū)分開的。你可以在事件中改變objectdatasource參數(shù)的名稱和值,這點(diǎn)與上面的sqldatasource示例類似。但是,如果你使用dataobjecttypename給update、insert和delete操作指定一個(gè)特殊的數(shù)據(jù)對(duì)象類型,就不可以修改參數(shù)名稱了--只能修改值。如果你需要修改參數(shù)名稱,就不要使用dataobjecttypename,只能用代碼在數(shù)據(jù)源事件中手動(dòng)地構(gòu)造適當(dāng)?shù)臄?shù)據(jù)對(duì)象。
上面我們用到的所有數(shù)據(jù)源參數(shù)都是input參數(shù),用于把值傳遞到數(shù)據(jù)源操作中。參數(shù)可以是雙向的,例如inputoutput、output和returnvalue參數(shù)。你可以使用參數(shù)對(duì)象的direction屬性來指定參數(shù)的方向。如果需要在數(shù)據(jù)源操作完成之后檢索這些參數(shù)的值,就需要處理適當(dāng)?shù)牟僮骱螅╬ost-operation)事件(例如selected、updated、inserted或deleted事件),從傳遞到這些事件的事件參數(shù)中獲取參數(shù)值。sqldatasourcestatuseventargs擁有command屬性,你可以使用它來獲取返回值和輸出參數(shù),如下面的例子所示。請(qǐng)注意,對(duì)于雙向參數(shù)來說,把sqldatasource中的parameter對(duì)象的size屬性設(shè)置為適當(dāng)?shù)闹凳欠浅V匾摹?br>
<asp:sqldatasource id="sqldatasource1" ……>
<selectparameters>
<asp:parameter direction="output" name="timestamp" type="datetime" />
<asp:parameter direction="returnvalue" name="returnvalue" type="int32" />
</selectparameters>
</asp:sqldatasource>
為了實(shí)現(xiàn)這個(gè)目標(biāo),objectdatasourcestatuseventargs類型支持outputparameters集合和returnvalue屬性,如下面一個(gè)例子所示。請(qǐng)注意,在這種情況下,update操作的返回值是用于檢測(cè)操作所影響的行數(shù)的。
protected sub objectdatasource1_selected(byval sender as object, byval e as objectdatasourcestatuseventargs)
response.write("record count: " & server.htmlencode(e.outputparameters("totalcount")))
end sub
protected sub objectdatasource1_updated(byval sender as object, byval e as objectdatasourcestatuseventargs)
response.write("rows affected: " & server.htmlencode(e.returnvalue) & "<br/>")
end sub
<asp:objectdatasource id="objectdatasource1" ……>
<updateparameters>
<asp:parameter name="contactname" type="string" />
</updateparameters>
<selectparameters>
<asp:parameter direction="output" name="totalcount" type="int32" />
</selectparameters>
</asp:objectdatasource>
輸出參數(shù)的另一種通常的用途是檢索插入數(shù)據(jù)庫的行的主鍵值,而該主鍵列是一個(gè)標(biāo)識(shí)列(在這種情況下,在插入操作的參數(shù)中沒有指定鍵值,該鍵值是在插入操作發(fā)生時(shí),數(shù)據(jù)庫服務(wù)器自動(dòng)生成的)。下面的例子演示了這種技術(shù)。
protected sub sqldatasource1_inserted(byval sender as object, byval e as system.web.ui.webcontrols.sqldatasourcestatuseventargs)
response.write("record inserted: " & server.htmlencode(e.command.parameters("@contactid").value) & "<br/>")
end sub
<asp:sqldatasource id="sqldatasource1" ……>
……
<insertparameters>
<asp:parameter name="contactname" type="string" />
<asp:parameter direction="output" name="contactid" type="int32" />
</insertparameters>
</asp:sqldatasource>