【问题标题】:asp:SqlDataSource with ROWVERSION (TIMESTAMP)asp:SqlDataSource 与 ROWVERSION (TIMESTAMP)
【发布时间】:2021-09-03 18:17:26
【问题描述】:

我遇到了 .NET(框架,带 WinForm 和 WebForms)/MS SQL 项目,其中数据库中的重要表包含一个 TIMESTAMP(又名 ROWVERSION)列(称为 tsModified)以防止并发问题。此外,该项目不允许应用层直接与表交互(而是所有 CRUD 和业务逻辑都必须通过存储过程完成)。

让我发疯的一件事是如何在 UPDATE 期间使用可以解释 TIMESTAMP 列的 SqlDataSource。

CRUD procs 的基本形式如下:

CREATE PROC Customer_List
  @pk_Customer INT = null
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
IF NOT EXISTS (SELECT TOP 1 1 FROM Customer where id=@id and tsModified=@tsModified)
    Return; --actually RAISEERROR w/ a concurrency alert telling the user to refresh & try again

UPDATE Customer SET [param/value pairs] WHERE id = @id;

当然,您可以手动定义部分类和方法来解释 tsModified,然后使用 asp:ObjectDataSource,但这是额外的工作。我只想方便地在表单上放置一个 asp:SqlDataSource,然后继续我的一天。

但是... SqlDataSource 不喜欢将 TIMESTAMP 作为参数。事实上,我确实花了几天时间研究如何使这项工作发挥作用,并且遇到了很多其他人遇到同样的问题。

我终于明白了。请参阅下面的答案。

【问题讨论】:

    标签: asp.net sqldatasource sql-timestamp database-concurrency rowversion


    【解决方案1】:

    以下是在使用存储过程时如何使用带有 asp:SqlDataSource 的 MS SQL ROWVERSION (TIMESTAMP) 列来处理并发。

    像这样设置你的 SqlDataSource:

    <asp:SqlDataSource ID="dsRegs" runat="server" OnUpdating="dsRegs_Updating" ConnectionString="[your connstr]" InsertCommand="RegulatoryAgency_Insert" InsertCommandType="StoredProcedure" SelectCommand="RegulatoryAgency_List" SelectCommandType="StoredProcedure" UpdateCommand="RegulatoryAgency_Update" UpdateCommandType="StoredProcedure">
                <InsertParameters>
                    <asp:Parameter Name="RegulatoryCode" Type="String" />
                    <asp:Parameter Name="RegulatoryName" Type="String" />
                    <asp:Parameter Name="RegulatoryState" Type="String" />
                </InsertParameters>
                <SelectParameters>
                    <asp:Parameter Name="pk_RegulatoryAgency" Type="DBNull" />
                </SelectParameters>
                <UpdateParameters>
                    <asp:Parameter Name="pk_RegulatoryAgency" Type="Int32" />
                    <asp:Parameter Name="RegulatoryCode" Type="String" />
                    <asp:Parameter Name="RegulatoryName" Type="String" />
                    <asp:Parameter Name="RegulatoryState" Type="String" />
                    <asp:Parameter Direction="InputOutput" Name="tsModified" Type="Empty" />
                </UpdateParameters>
            </asp:SqlDataSource>
    

    需要注意的重要事项是:

    1. 在 UpdateParameters 中,tsModified 是 TIMESTAMP 值和 Type="Empty"。
    2. OnUpdating 设置为 dsRegs_Updating 事件。

    现在是后面的代码:

        /// <summary>
        /// When editing for this record/row begins in the grid, we need to get the primary key from the row, 
        /// and then stuff the TIMESTAMP (tsModified) into a Session variable so it persists
        /// </summary>
        protected void gvRegs_StartRowEditing(object sender, DevExpress.Web.Data.ASPxStartRowEditingEventArgs e)
        {
            int pk = (int)e.EditingKeyValue;
            var db = new myDataContext();
            var ra = db.RegulatoryAgency_List(pk).First();
            Session["tsModified"] = ra.tsModified;
        }
    
        /// <summary>
        /// Before we call the database, convert the Session var back the original Linq-to-SQL type (System.Data.Linq.Binary), then
        /// convert it to a (byte) array, and update the SqlDataSource parameter with the correct value.
        /// </summary>
        protected void dsRegs_Updating(object sender, SqlDataSourceCommandEventArgs e)
        {
            DbParameter dp = e.Command.Parameters["@tsModified"];
            dp.Value = ((System.Data.Linq.Binary)Session["tsModified"]).ToArray();
        }
    

    在本例中,前面使用的是 DevExpress ASPxGridView,但数据绑定和事件在其他数据绑定控件上应该类似。当行编辑开始时,我们从数据库中提取记录的 tsModified 值并将其放入 Session 变量中。然后 SqlDataSource 触发其 Updating 事件,我们获取 Session 变量,将其转换回原来的格式(在我的例子中是 System.Data.Linq.Binary,因为这个示例使用的是 Linq-to-SQL),最后是最后一个技巧是您不能将 TIMESTAMP 值作为二进制、varbinary 或字节传递 - 必须作为 btye[] 发送,.ToArray() 正在处理。

    使用这样的代码,我可以通过 SqlDataSource 成功地 SELECT、INSERT、UPDATE 和 DELETE,并且数据库中的 tsModified (TIMESTAMP) 值按预期递增。

    【讨论】:

      猜你喜欢
      • 2018-03-02
      • 1970-01-01
      • 2010-11-05
      • 1970-01-01
      • 2014-08-17
      • 1970-01-01
      • 1970-01-01
      • 2019-07-31
      • 2014-05-20
      相关资源
      最近更新 更多