如何让调用存储过程的asp:SqlDataSource支持TIMESTAMP(ROWVERSION)并发校验
.NET Framework中SqlDataSource对接SQL Server TIMESTAMP并发校验解决方案
项目背景
- 项目基于.NET Framework,覆盖WinForm、WebForms场景,对接MS SQL Server数据库
- 核心业务表均包含
tsModifiedTIMESTAMP(又称ROWVERSION)列,用于避免并发更新冲突 - 项目规范要求所有CRUD操作及业务逻辑必须通过存储过程实现,应用层不允许直接操作数据表
核心诉求
希望直接使用拖拽asp:SqlDataSource控件的便捷开发方式,实现UPDATE操作时自动传递TIMESTAMP列参数完成并发校验,无需额外编写分部类使用asp:ObjectDataSource增加开发工作量。
项目现有存储过程基础结构
CREATE PROC Customer_List @pk_Customer INT = null AS SELECT id, name, tsModified FROM Customer WHERE @pk_Customer IS NULL OR @pk_Customer = id; CREATE PROC Customer_Update @id INT, @name varchar, @tsMod TIMESTAMP AS IF NOT EXISTS (SELECT TOP 1 1 FROM Customer where id=@id and tsModified=@tsModified) -- 实际业务中此处抛出并发冲突错误,提示用户刷新后重试 RAISERROR('数据已被其他用户修改,请刷新页面后重试', 16, 1) RETURN UPDATE Customer SET name = @name WHERE id = @id;
具体解决方案
仅需要对asp:SqlDataSource做三处配置调整即可实现需求:
- 配置查询存储过程返回的
tsModified列作为并发校验字段
首先设置SqlDataSource的ConflictDetection属性为CompareAllValues,同时将tsModified加入DataKeyNames属性:<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConflictDetection="CompareAllValues" DataKeyNames="id,tsModified" SelectCommand="Customer_List" SelectCommandType="StoredProcedure" UpdateCommand="Customer_Update" UpdateCommandType="StoredProcedure"> - 显式定义UPDATE存储过程的TIMESTAMP参数类型
在UpdateParameters集合中手动指定@tsMod参数的类型为Object,方向为Input,并且绑定原始值:<UpdateParameters> <asp:Parameter Name="id" Type="Int32" /> <asp:Parameter Name="name" Type="String" /> <asp:Parameter Name="tsMod" Type="Object" Direction="Input" SourceField="tsModified" OriginalValuesOnly="true" /> </UpdateParameters> </asp:SqlDataSource> - 确保绑定控件(如GridView、FormView)保留
tsModified字段原始值
如果使用GridView展示数据,需要在列定义中添加隐藏的tsModified绑定列:<asp:GridView ID="GridView1" runat="server" DataSourceID="SqlDataSource1" DataKeyNames="id,tsModified"> <Columns> <asp:BoundField DataField="id" HeaderText="客户ID" ReadOnly="true" /> <asp:BoundField DataField="name" HeaderText="客户名称" /> <asp:BoundField DataField="tsModified" Visible="false" /> <asp:CommandField ShowEditButton="true" /> </Columns> </asp:GridView>
注意:不要将
tsModified列的类型设置为Binary,SqlDataSource对二进制类型的原始值传递存在已知bug,设置为Object类型会自动保留TIMESTAMP的二进制原始值,可正常完成并发校验。
内容的提问来源于stack exchange,提问作者Ted Krapf
相关产品推荐
相关产品推荐

