【问题标题】:Exception when updating row with rowversion?使用 rowversion 更新行时出现异常?
【发布时间】:2017-07-14 09:34:38
【问题描述】:

我有一张像这样的表:

CREATE TABLE [dbo].[akut_prioritering]
(
    [behandling_id] [int] NOT NULL,
    [akutstatus] [int] NOT NULL,
    [nasta_dag] [bit] NOT NULL,
    [sort_order] [bigint] NOT NULL,
    [rowversion] [timestamp] NOT NULL,

    CONSTRAINT [XPKakut_prioritering] 
        PRIMARY KEY CLUSTERED ([behandling_id] ASC)
) ON [PRIMARY]

然后我有这个存储过程,它试图更新这个表中的行:

ALTER PROCEDURE [dbo].[akutlistaSave] 
    @behandlingSortOrder dbo.akutlista_sortorder_tabletype READONLY
AS
BEGIN
    SET NOCOUNT ON;

    DECLARE @behandlingId INT;
    DECLARE @sortOrder BIGINT;
    DECLARE @rowversion ROWVERSION;

    DECLARE sortOrderCursor CURSOR LOCAL SCROLL STATIC FOR
        SELECT behandling_id, sort_order FROM @behandlingSortOrder

    OPEN sortOrderCursor

    BEGIN TRAN

        FETCH NEXT FROM sortOrderCursor INTO @behandlingId, @sortOrder, @rowversion

        WHILE @@FETCH_STATUS = 0
        BEGIN
            IF EXISTS(SELECT * 
                      FROM akut_prioritering ap 
                      WHERE ap.behandling_id = @behandlingId 
                        AND ap.rowversion = @rowversion)
            BEGIN
                UPDATE akut_prioritering
                SET sort_order = @sortOrder
                WHERE behandling_id = @behandlingId;
            END
            ELSE
            BEGIN
                RAISERROR ('Rowversion not correct.', 16, 1);
            END

            FETCH NEXT FROM sortOrderCursor INTO @behandlingId, @sortOrder, @rowversion
        END

        CLOSE sortOrderCursor

        SELECT 
            ap.behandling_id, ap.rowversion 
        FROM 
            akut_prioritering ap 
        INNER JOIN 
            @behandlingSortOrder bso ON ap.behandling_id = bso.behandling_id;

        DEALLOCATE sortOrderCursor
END

inparameter 类型如下所示:

CREATE TYPE [dbo].[akutlista_sortorder_tabletype] AS TABLE 
            (
                [behandling_id] [int] NULL,
                [sort_order] [bigint] NULL,
                [rowversion] [timestamp] NULL
            )

运行时我得到一个SqlException

无法将显式值插入时间戳列。将 INSERT 与列列表一起使用以排除时间戳列,或将 DEFAULT 插入时间戳列。

据我了解,rowversion 列应自动更新为新值,在我的情况下没有理由手动设置它。

【问题讨论】:

  • 如果您最终使用游标执行单个更新,则使用存储过程批量执行乐观更新没有多大意义。这最终比发送单个 UPDATE 语句。更好的选择是在目标表和输入之间连接,并仅更新具有匹配行版本的行。 然后选择并返回所有具有匹配行版本的那些
  • 一个 ORM 会产生类似的代码没有光标引入的惩罚。

标签: sql-server rowversion


【解决方案1】:

您不能在dbo.akutlista_sortorder_tabletype 中设置rowversion 值,因为它不可更新:它是自动生成的

但是,rowversion(又名已弃用的timestamp)只是一个带有一些特殊规则的 (var)binary(8)。您可以在 dbo.akutlista_sortorder_tabletype 中定义和设置 (var)binary(8) 并在 UPDATE 中进行比较

来自第一个链接

不可为空的 rowversion 列在语义上等同于 binary(8) 列。可为空的 rowversion 列在语义上等同于 varbinary(8) 列。

【讨论】:

    【解决方案2】:

    您似乎正在尝试在自定义表类型中 insert timestamp 值,然后将其传递给您的存储过程。正如您的错误所暗示的那样,您不能将 insert 显式 timestamp 值放入 timestamp 列中。

    您需要找到一种不同的方式将表值传递给此存储过程才能工作。

    【讨论】:

    • 这不是 OP 所要求的。该代码似乎没有在任何地方修改行版本
    • @PanagiotisKanavos 存储过程接受一个自定义表类型作为参数,其中包含一个timestamp 列,如果没有inserted 直接将任何timestamp 比较无用。
    • 这不是问题。允许比较。问题是 TVP 甚至不能被 client 填充,因为rowversion 不能被修改
    • @PanagiotisKanavos 所以你可以说问题是 OP 是“trying to insert a timestamp value in a custom table type”我的答案?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-30
    相关资源
    最近更新 更多