SSIS - 自动增量字段未正确插入数据流任务

时间:2021-05-03 14:04:35

标签: sql-server ssis

我正在尝试使用 ssis 将数据从一个数据库复制到另一个数据库。我使用 SQL Server 导入和导出向导创建了 dtsx 包。 我正在复制的表有一个列名“Id”,另一个表的名称是“ModuleCategoryId”,我将它们映射在一起。

ModuleCategoryId 是身份,自动递增 1。 在源数据库中,Id 没有排序,如下所示:

  • 32 Name1
  • 14 Name2
  • 7 Name3

执行数据流后,目标DB如下所示:

  • 1 名 1
  • 2 Name2
  • 3 Name3

我在向导中启用了身份插入,但这没有任何作用。 Column mapping

目标数据库是用实体框架制作的,代码优先。

如果我明确关闭 ValueGeneratedOnAdd 并重新制作目标数据库,数据将被正确传输,但我想知道是否有一种方法可以在不关闭自动增量的情况下传输所有数据,然后重新打开它。

如果我手动为该表设置了 Identity Insert,我可以插入带有我想要的任何 ModuleCategoryId 的行,因此它必须与数据流有关。

1 个答案:

答案 0 :(得分:1)

表定义是表定义 - 无论 ORM 工具可能覆盖的语法糖如何。

我创建了一个源表和目标表,并填充了源以匹配您提供的数据。我也在目标表上定义了标识属性。我不知道这是否是在 API 中实现的 ValueGeneratedOnAdd,但几乎必须是否则启用身份插入应该失败(如果 UI 甚至允许它)。

IDENTITY 属性允许您使用您想要的任何初始值为其设定种子。对于目标表,我以有符号整数允许的最小值作为种子,这样如果身份插入不起作用,结果值将看起来非常“错误”

DROP TABLE IF EXISTS dbo.SO_67370325_Source;
DROP TABLE IF EXISTS dbo.SO_67370325_Destination;

CREATE TABLE dbo.SO_67370325_Source
(
    Id int IDENTITY(1,1) NOT NULL
,   Name varchar(50)
);
CREATE TABLE dbo.SO_67370325_Destination
(
    ModuleCategoryId int IDENTITY(-2147483648,1) NOT NULL
,   Name varchar(50)
);

CREATE TABLE dbo.SO_67370325_Destination_noident
(
    ModuleCategoryId int NOT NULL
,   Name varchar(50)
);

SET IDENTITY_INSERT dbo.SO_67370325_Source ON;
INSERT INTO DBO.SO_67370325_Source
(
    Id
,   Name
)
VALUES
    (32, 'Name1')
,   (14, 'Name2')
,   (7, 'Name3');
SET IDENTITY_INSERT dbo.SO_67370325_Source OFF;

INSERT INTO dbo.SO_67370325_Source
(
    Name
)
OUTPUT Inserted.*
VALUES
(
    'Inserted naturally' -- Name - varchar(50)
);

除了你提供的 3 个值之外,我添加了第四个,如果你运行提供的查询,你会看到生成的 ID 可能是 33。源表创建的标识为 1,但显式标识插入源表表将种子值提前到 32。假设没有其他活动发生,下一个值将是 33,因为我们的增量是 1。

说了这么多,我已经建立了 3 个场景。在导入导出向导中,我检查了 Identity Insert 并将 Id 映射到 ModuleCategoryId 并运行了包。

ModuleCategoryId|Name
32|Name1
14|Name2
7|Name3
33|Inserted naturally

目标表中的数据与源表中的数据相同 - 正如预期的那样。此时,身份种子位于 33,我可以使用一些我不方便的 DBCC 检查命令进行验证。

下一个案例是采用相同的包并取消选中 Identity Insert 属性。这将变得无效,因为我会收到错误报告

<块引用>

插入只读列“ModuleCategoryId”失败

唯一的选择是将 Id 取消映射到 ModuleCategoryId。假设我像以前一样加载到同一张表,我会看到类似这样的数据

ModuleCategoryId|Name
34|Name1
35|Name2
36|Name3
37|Inserted naturally

如果我从来没有将记录放入这个表中,那么我会得到这样的结果

ModuleCategoryId|Name
-2147483648|Name1
-2147483647|Name2
-2147483646|Name3
-2147483645|Inserted naturally

如果没有我的来源明确订购,则无法保证订购结果。我经常打这场仗。除非您明确要求,否则 SQL 引擎没有义务按主键顺序或任何其他此类顺序返回数据。如果存储了以下结果,则同样有效。

ModuleCategoryId|Name
34|Inserted naturally
35|Name1
36|Name2
37|Name3

如果您有数据需要根据源表中Id的升序插入到目标表中,在导入/导出向导中,您需要转到询问您是否要插入的屏幕选择表或编写查询并选择查询的第二个选项。然后您将编写 SELECT * FROM dbo.SO_67370325_Source ORDER BY Id; 或任何您的源表的名称。

加载 SO_67370325_Destination_noident 的最终测试演示了一个没有定义身份属性的表。如果我不将 Id 映射到 ModuleCategoryId,则该包将失败,因为该列被定义为 NOT NULL。当我将 Id 映射到 ModuleCategoryId 时,我将看到与第一个 (7,14,32,33) 相同的结果,但是,对目标表的每个后续插入都必须提供自己的 Id,该 Id 可能与也可能不一致你的 FluentAPI 东西可以。

类似的问题/答案Error 0xc0202049: Data Flow Task 1: Failure inserting into the read-only column

相关问题