UPDATE [Products] SET [ProductName] = @ProductName, [UnitPrice] = @UnitPrice, [Discontinued] = @Discontinued WHERE [ProductID] = @original_ProductID AND [ProductName] = @original_ProductName AND [UnitPrice] = @original_UnitPrice AND [Discontinued] = @original_Discontinued
表Products的UnitPrice列的值允许为NULL,如何某条记录的UnitPrice确实为NULL,那么WHERE字句的“[UnitPrice] = @original_UnitPrice”总是为False,NULL = NULL总是返回False。所以凡是y包含NULL值的记录不能被编辑或删除,因为UPDATE和DELETE命令中的WHERE字句不能返回记录。
注意:这个漏洞最早于2004年6月报告给微软,据业内传言,微软将在ASP.NET的下一个版本修补该漏洞。
为修补该漏洞,我们需要在UpdateCommand和DeleteCommand属性里手工修改所有允许为NULL值的列。一般来说,将[ColumnName] = @original_ColumnName to改成:
( ([ColumnName] IS NULL AND @original_ColumnName IS NULL) OR ([ColumnName] = @original_ColumnName) )
你可以在属性窗口的UpdateQuery或DeleteQuery选项的代码声明里修改,或者在设置数据源向导的“指定自定义SQL语句或存储过程”选项的“更新”和“删除”标签里修改。确保在UpdateCommand和DeleteCommand的WHERE字句里做相同的修改。如下:
UPDATE [Products] SET [ProductName] = @ProductName, [UnitPrice] = @UnitPrice, [Discontinued] = @Discontinued WHERE [ProductID] = @original_ProductID AND [ProductName] = @original_ProductName AND (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL) OR ([UnitPrice] = @original_UnitPrice)) AND [Discontinued] = @original_Discontinued DELETE FROM [Products] WHERE [ProductID] = @original_ProductID AND [ProductName] = @original_ProductName AND (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL) OR ([UnitPrice] = @original_UnitPrice)) AND [Discontinued] = @original_Discontinued
第2步:为GridView控件添加编辑和删除项
当设置SqlDataSource控件支持开放式并发时,我们需要在页面上添加一个数据Web控件,以便执行开放式并发控制。本章我们添加一个提供编辑和删除功能的GridView控件。从工具箱拖一个GridView到页面上,设置其ID为Products,并绑定到第一步添加的SqlDataSource控件ProductsDataSourceWithOptimisticConcurrency,最后启用其“编辑”和“删除”功能。
图6:将GridView绑定到SqlDataSource并启用编辑和删除功能
添加GridView控件后,优化其界面。将ProductID列移除;将ProductName列的HeaderText属性设置为“Product”;同样,UnitPrice列的设置为“Price”。另外,我们最好为ProductName添加一个RequiredFieldValidator控件;为UnitPrice添加一个CompareValidator控件(确保其为格式化的数字值)。参考教程Customizing the Data Modification Interface看如何自定义GridView界面。
注意:必须确保激活GridView控件的view state(视图状态),因为GridView控件传递原始值时,将原始值保存在view state中。
对GridView控件做了这些修改后,GridView控件和SqlDataSource控件的声明代码看起来和下面的差不多:
<asp:SqlDataSource runat="server" ConflictDetection="CompareAllValues" ConnectionString="<%$ ConnectionStrings:NORTHWNDConnectionString %>" DeleteCommand= "DELETE FROM [Products] WHERE [ProductID] = @original_ProductID AND [ProductName] = @original_ProductName AND (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL) OR ([UnitPrice] = @original_UnitPrice)) AND [Discontinued] = @original_Discontinued" OldValuesParameterFormatString= "original_{0}" SelectCommand= "SELECT [ProductID], [ProductName], [UnitPrice], [Discontinued] FROM [Products]" UpdateCommand= "UPDATE [Products] SET [ProductName] = @ProductName, [UnitPrice] = @UnitPrice, [Discontinued] = @Discontinued WHERE [ProductID] = @original_ProductID AND [ProductName] = @original_ProductName AND (([UnitPrice] IS NULL AND @original_UnitPrice IS NULL) OR ([UnitPrice] = @original_UnitPrice)) AND [Discontinued] = @original_Discontinued"> <DeleteParameters> <asp:Parameter Type="Int32" /> <asp:Parameter Type="String" /> <asp:Parameter Type="Decimal" /> <asp:Parameter Type="Boolean" /> </DeleteParameters> <UpdateParameters> <asp:Parameter Type="String" /> <asp:Parameter Type="Decimal" /> <asp:Parameter Type="Boolean" /> <asp:Parameter Type="Int32" /> <asp:Parameter Type="String" /> <asp:Parameter Type="Decimal" /> <asp:Parameter Type="Boolean" /> </UpdateParameters> </asp:SqlDataSource> <asp:GridView runat="server" AutoGenerateColumns="False" DataKeyNames="ProductID" DataSourceID="ProductsDataSourceWithOptimisticConcurrency"> <Columns> <asp:CommandField ShowDeleteButton="True" ShowEditButton="True" /> <asp:BoundField DataField="ProductName" HeaderText="Product" SortExpression="ProductName" /> <asp:BoundField DataField="UnitPrice" HeaderText="Price" SortExpression="UnitPrice" /> <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued" SortExpression="Discontinued" /> </Columns> </asp:GridView>