下面的代码示例显示了SqlDataSource控件在OverwriteChanges和CompareAllValues模式下使用的典型的SQL命令。ID字段被假定为主键字段。请注意,后面一个命令在WHERE子句中比较数据行的所有原始值,而不是仅仅比较主键。在这种情况下,数据源的OldValuesParameterFormatString需要被设置为"original_{0}"。
SELECT;[ID],;[Name],;[Address];from;[Contacts];
--;OverwriteChanges
UPDATE;[Contacts];SET;[Name];=;@Name,;[Address];=;@Address;WHERE;[ID];=;@ID
DELETE;FROM;[Contacts];WHERE;[ID];=;@ID
--;CompareAllValues
UPDATE;[Contacts];SET;[Name];=;@Name,;[Address];=;@Address;WHERE;[ID];=;@original_ID;
AND;[Name];=;@original_Name;AND;[Address];=;@original_Address
DELETE;FROM;[Contacts];WHERE;[ID];=;@original_ID;AND;[Name];=;@original_Name;
AND;[Address];=;@original_Address;
请注意,Insert操作不需要OldValues,ConflictDetection只对Update和Delete操作有意义。
下面的例子演示了冲突发生时的行为。为了运行这个例子,你必须在两个独立的浏览器窗口中打开例子的两个实例(两次点击"Run;Sample")。接着在两个窗体的同一行上都点击"Edit"按钮,使该行进入编辑模式。在第一个窗口中改变一个值并点击"Update",请注意这个更新是成功的。在第二个窗口中,在该行中输入一个新值并点击"Update",这个更新操作没有成功,因为下层数据行的值已经被第一个更新操作改变过了。这个示例检测了Updated或Deleted事件参数的AffectedRows属性,它为0确认了冲突发生了。
<script;runat="server">
Protected;Sub;SqlDataSource1_Updated(sender;As;Object,;e;As;SqlDataSourceStatusEventArgs)
If;e.AffectedRows;=;0;Then
Response.Write("Row;changed,;update;aborted<br;/>")
End;If
End;Sub
Protected;Sub;SqlDataSource1_Deleted(sender;As;Object,;e;As;SqlDataSourceStatusEventArgs)
If;e.AffectedRows;=;0;Then
Response.Write("Row;changed,;delete;aborted<br;/>")
End;If
End;Sub
</script>;
当Update或Delete使用模板化UI的时候,使用了Bind语法的双向(two-way)数据绑定字段的旧值都会被保留。对于Delete来说,这意味着在ItemTemplate中你必须给数据绑定的值使用Bind语法,其目的是为了保留删除操作所需要的旧值。下面的例子演示了这种技术。
<asp:GridView;……>
<Columns>
<asp:CommandField;ShowDeleteButton="True";ShowEditButton="True";/>
<asp:TemplateField;HeaderText="ContactID";InsertVisible="False";SortExpression="ContactID">
<ItemTemplate>
<asp:Label;ID="Label1";runat="server";Text='<%#;Bind("ContactID");%>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:Label;ID="Label3";runat="server";Text='<%#;Eval("ContactID");%>'></asp:Label>
</EditItemTemplate>;
</asp:TemplateField>
<asp:TemplateField;HeaderText="ContactName";SortExpression="ContactName">
<ItemTemplate>
<asp:Label;ID="Label2";runat="server";Text='<%#;Bind("ContactName");%>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox;ID="TextBox1";runat="server";Text='<%#;Bind("ContactName");%>'></asp:TextBox>
</EditItemTemplate>
</asp:TemplateField>
</Columns>
</asp:GridView>;
你可以温和地处理冲突检测错误,可以通过提示用户下层数据被改变了,向用户显示改变过的值,;让用户选择提交或放弃自己的操作。下面的例子演示处理冲突检测的一种可行方法。请注意,DetailsView的RowUpdated事件参数传递了可用于检测用户输入的值的字典。你还可以设置这个事件参数的KeepInEditMode属性,使用户在决定如何处理冲突期间,DetailsView处于编辑模式。这个例子所试验方法与上面一个例子类似,同时打开两个窗口来创建冲突更新。
Protected;Sub;DetailsView1_ItemUpdated(ByVal;sender;As;Object,;ByVal;e;As;System.Web.UI.WebControls.DetailsViewUpdatedEventArgs)
If;e.AffectedRows;=;0;Then
';使DetailsView处于编辑模式并与数据库同步
e.KeepInEditMode;=;True
DetailsView1.DataBind()
';用用户输入的值重新填充DetailsView
Dim;t;As;TextBox
t;=;DetailsView1.Rows(1).Cells(1).Controls(0)
t.Text;=;e.NewValues("OrderDate")
t;=;DetailsView1.Rows(2).Cells(1).Controls(0)
t.Text;=;e.NewValues("ShipCountry")
ErrorPanel.Visible;=;True
Else
ErrorPanel.Visible;=;False
End;If
End;Sub
Protected;Sub;DetailsView1_ModeChanging(ByVal;sender;As;Object,;ByVal;e;As;System.Web.UI.WebControls.DetailsViewModeEventArgs)
If;e.CancelingEdit;=;True;AndAlso;ErrorPanel.Visible;=;True;Then
ErrorPanel.Visible;=;False
End;If
End;Sub;
使用ObjectDataSource的时候,情况也类似。请注意,由于数据源的ConflictDetection属性被设置为CompareAllValues,数据源将查找一个可接受Contact对象的每个字段的原始值的UpdateContact重载。
你还可以同时使用DataObjectTypeName属性和CompareAllValues。在这种情况下,ObjectDataSource查找仅接受两个参数(都是Contact)的UpdateContact重载。第一个参数是存放新值的Contact对象,第二个参数是存放旧值的Contact对象。
标签: