DACPAC 和 SQL 序列

问题描述 投票:0回答:4

我有一个 Visual Studio 数据库项目 (DACPAC),其中包含许多 SQL 序列。但是,当我部署 DACPAC 时,它总是将序列值重置为创建脚本中包含的默认值(在本例中为 1)。例如

CREATE SEQUENCE [dbo].[MySequence]
AS INT
START WITH 1
INCREMENT BY 1;

任何人都可以建议一种方法来指示 DACPAC 忽略序列起始值,或者某种方法让 DACPAC 恢复正确的值作为部署后步骤吗?

提前致谢

sql-server visual-studio sql-server-data-tools dacpac sqlpackage
4个回答
16
投票

这是使用 SSDT 工具时序列的一个已知问题。有几种解决方案。

  1. 发布时忽略序列对象。
  2. 使用自定义部署过滤器忽略起始值。
  3. 部署上线后,使用
    sp_sequence_get_range
    而不是
    RESTART WITH
    来增加计数器。

1.发布时忽略序列对象

这是最简单的选项,但也是最尴尬的,因为这意味着您必须手动部署序列。 将以下内容添加到您的发布配置文件

<ExcludeSequences>True</ExcludeSequences>

或者,从命令行

/p:ExcludeObjectType=Sequences

2.使用自定义部署过滤器

首先下载AgileSqlClub 的部署过滤器。 然后将以下内容添加到您的部署配置文件中:

<AdditionalDeploymentContributors>AgileSqlClub.DeploymentFilterContributor</AdditionalDeploymentContributors>
<AdditionalDeploymentContributorArguments>SqlPackageFilter=IgnoreName(Order_No_Seq)</AdditionalDeploymentContributorArguments>

或者,从命令行:

/p:AdditionalDeploymentContributors=AgileSqlClub.DeploymentFilterContributor
/p:AdditionalDeploymentContributorArguments="SqlPackageFilter=IgnoreName(Order_No_Seq)"

3.使用
sp_sequence_get_range

为此,不要在生产服务器上使用

RESTART WITH
来更改起始值,而是使用:

DECLARE @range_first_value SQL_VARIANT;
EXEC sp_sequence_get_range
    @sequence_name = 'MySequence',
    @range_size = 1000,
    @range_first_value = @range_first_value OUTPUT;

这样起始值将始终与部署脚本中的预期值匹配。


资源


1
投票

有点晚了,但我也遇到了这个问题。引起很多头痛。

我已向 Microsoft 提出罚单:https://developercommunity.visualstudio.com/content/problem/732407/dacpac-resets-sequences.html

我们当前的解决方法是使用部署前和部署后脚本在应用 dacpac 之前捕获所有序列值,然后将其重置回来。

这远非理想。


0
投票

我们通过创建一个在部署后执行的过程来重置具有最大值的序列来克服这个问题

我们创建了自己的 dbo.sequence 表,该表记录了表及其创建序列的主键列,如果/当我们创建新表和序列时,我们也会保持更新

然后在部署后运行此代码

        DECLARE UpdateMaxValue CURSOR FAST_FORWARD
   FOR SELECT DISTINCT 
              TableName
            , PrimaryKeyColumn AS ColumnName
       FROM dbo.Sequence AS A
       WHERE TableName NOT IN ( 'Bulk', 'PartyCd', 'PoolNum' )
       ORDER BY TableName
              , PrimaryKeyColumn;
   OPEN UpdateMaxValue;
   WHILE 1 = 1
    BEGIN
     FETCH NEXT FROM UpdateMaxValue INTO @TableName
                                       , @ColumnName;
     SET @CurrentTime = CONVERT(VARCHAR(25), GETDATE(), 121);
     IF @@FETCH_STATUS <> 0
      BEGIN
       BREAK;
     END;
     SET @SQL = ' 
SET NOCOUNT ON

IF OBJECT_ID(''dbo.' + @TableName + ''') IS NOT NULL
 BEGIN
  RAISERROR(''/* ' + @CurrentTime + ' --  ALTER SEQUENCE [dbo].[' + @TableName + 'Seq] -- */'', 0, 1) WITH NOWAIT;

    DECLARE @MaxValue INT = (SELECT ISNULL(MAX(' + @ColumnName + ') + 2,0) FROM dbo.' + @TableName + ') 
  
    EXEC(''ALTER SEQUENCE [dbo].[' + @TableName + 'Seq] RESTART WITH ''+@MaxValue+'''')   
 END
';
     EXEC (@SQL);
    END;
   CLOSE UpdateMaxValue;
   DEALLOCATE UpdateMaxValue;

0
投票

我们与这个问题斗争了很长时间,最终发现,当我们在重置后更正序列时,这会以某种方式将其标记为脏,导致它在下次部署期间被重置。 在我们看来,这是由下面查询中的 ALTER 语句引起的:

DECLARE  @sequenceNumber AS NVARCHAR(MAX)
DECLARE  @sql NVARCHAR(MAX)
SELECT TOP 1 @sequenceNumber = CONVERT(VARCHAR, CAST(SUBSTRING([dossier].[DossierNumber], 6, 4) AS INT) + 1)  FROM [Dossier] [dossier] WHERE [dossier].[DossierNumber] LIKE CONCAT(YEAR(GETDATE()), '%') ORDER BY [DossierNumber] DESC
SET @sql = 'ALTER SEQUENCE [BSF_SEQ_DOSSIER_NUMBER] RESTART WITH ' + @sequenceNumber
PRINT @sequenceNumber
PRINT @sql
 
EXEC(@sql)
 
GO

运行此查询后(因为序列在上一次部署期间被重置),这将标记要在下一次部署期间重置的序列(这迫使我们再次运行此查询,以无限循环结束)。

通过以下查询,问题消失。我们只需要运行此查询一次,之后在任何后续部署期间将不再重置序列。

DECLARE  @sequenceNumberTarget AS INT;
DECLARE @sequenceNumberCurrentValue AS INT;
SELECT TOP 1 @sequenceNumberTarget = CONVERT(VARCHAR, CAST(SUBSTRING([dossier].[DossierNumber], 6, 4) AS INT)) FROM [Dossier] [dossier] WHERE [dossier].[DossierNumber] LIKE CONCAT(YEAR(GETDATE()), '%') ORDER BY [DossierNumber] DESC;
SELECT @sequenceNumberCurrentValue = CAST(current_value AS INT) FROM sys.sequences WHERE name = 'BSF_SEQ_DOSSIER_NUMBER';
PRINT CONCAT('Sequence number target: ', @sequenceNumberTarget);
PRINT CONCAT('Sequence number current value: ', @sequenceNumberCurrentValue);
WHILE (@sequenceNumberCurrentValue < @sequenceNumberTarget)
BEGIN
    SET @sequenceNumberCurrentValue = NEXT VALUE FOR [BSF_SEQ_DOSSIER_NUMBER];
END
© www.soinside.com 2019 - 2024. All rights reserved.