【问题标题】:SSIS - Auto increment field is not inserted correctly with data flow taskSSIS - 数据流任务未正确插入自动增量字段
【发布时间】:2021-05-03 14:04:35
【问题描述】:

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

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

  • 32 名称1
  • 14 名2
  • 7 姓名3

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

  • 1 姓名1
  • 2 名称2
  • 3 姓名3

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

目标数据库是使用实体框架创建的,代码优先。

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

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

【问题讨论】:

  • 你提到了“ValueGeneratedOnAdd”,但我没有这方面的参考——你能再解释一下吗?
  • 使用 FluentAPI 你可以设置 ValueGeneratedOnAdd 这意味着每次添加一行时,ID 需要增加 1。所以通常当添加一行时,我需要这个,但不是用于初始数据传输
  • FluentAPI 是实体框架的新名称?对于您定义的问题,SSIS 包中是否涉及 FluentAPI,还是数据“通常”如何进入源表或目标表?
  • FluentAPI 是一种配置类的方法,以便数据库反映您的需要。例如。设置表之间的关系,列的数据类型等。dtsx包中没有用到

标签: sql-server ssis


【解决方案1】:

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

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

IDENTITY 属性允许您使用所需的任何初始值对其进行播种。对于 taget 表,我以有符号整数允许的最小值为种子,这样如果身份插入不起作用,结果值看起来真的“错误”

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,但显式标识插入源table 将种子值提前到 32。假设没有其他活动发生,下一个值将是 33,因为我们的增量是 1。

话虽如此,我已经建立了 3 个场景。在 Import Export 向导中,我检查了 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,它可能与什么对齐也可能不对齐你的 FluentAPI 东西可以。

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

【讨论】:

  • 感谢您的回复。您提到的一件事是,如果您在向导中取消选中“身份插入”,则插入会引发错误。对我来说不是这样。即使我不选中它,行也会被转移。然后我查看了目标表中的 ModuleCategoryId 列,它被设置为 Identity,所以我认为如果未选中它应该会失败。作为附加测试,我尝试在没有激活身份插入的情况下向表中插入几行,但它应该失败。
  • 所以我决定在 Visual Studio 中从头开始制作 dtsx 包,并在 OLE DB 目标上将数据访问模式设置为表视图 - 快速加载,选中“保持身份”并取消选中“检查”约束”。对数据库中的所有表执行此操作。这解决了我的问题。我不知道向导中的“启用身份插入”复选框是否不起作用,或者这不是我的实际问题,但我让它以这种方式工作。再次感谢,您的评论让我想到了正确的方向!
猜你喜欢
  • 2022-01-03
  • 1970-01-01
  • 1970-01-01
  • 2017-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-09-09
相关资源
最近更新 更多