使用序列设置主 ID 时如何将数据批量插入表中
Posted
技术标签:
【中文标题】使用序列设置主 ID 时如何将数据批量插入表中【英文标题】:How to bulk insert data into a table when the primary ID is set with a sequence 【发布时间】:2019-09-09 12:58:10 【问题描述】:我正在尝试使用 SqlBulkCopy
将多行插入到 Id 列设置有序列的表中。序列和表格如下所示:
CREATE SEQUENCE [dbo].[MyTableId]
AS [int]
START WITH 1
INCREMENT BY 1
MINVALUE -2147483648
MAXVALUE 2147483647
CACHE 10
GO
CREATE TABLE [dbo].[MyTable](
[Id] [int] NOT NULL,
[SomeColumn] [int] NOT NULL,
[AnotherColumn] [nvarchar](100) NOT NULL
CONSTRAINT [PK_MyTable] PRIMARY KEY CLUSTERED
(
[Id] ASC
)
GO
ALTER TABLE [dbo].[MyTable] ADD
CONSTRAINT [DF_MyTable_Id]
DEFAULT (NEXT VALUE FOR [MyTableId]) FOR [Id]
GO
导入行的代码如下所示:
var table = new DataTable();
using (var adapter = new SqlDataAdapter($"SELECT TOP 0 * FROM dbo.MyTable", conn))
adapter.Fill(table);
foreach (Data d in data)
var row = table.NewRow();
row["SomeColumn"] = d.someColumnValue;
row["AnotherColumn"] = d.anotherColumnValue;
table.Rows.Add(row);
using (var bulk = new SqlBulkCopy(conn))
bulk.DestinationTableName = "dbo.MyTable";
bulk.WriteToServer(table);
将数据写入服务器时失败,因为
System.InvalidOperationException: 'Column 'Id' does not allow DBNull.Value.'
我尝试从表定义中删除 Id 列,但这只是将列序号减一。我尝试将 Id 行设置为:
table.Columns["Id"].AutoIncrement = true;
但这会忽略顺序,并且在重复运行导入时,会从 0 重新开始自动递增值。
如何指示服务器使用其序列生成新的 Id 值?或者是否可以在表中创建新行之前分别为序列生成多个值?
【问题讨论】:
您是否尝试过使用SqlBulkCopyColumnMapping
来配置列列表?如果这没有帮助,想到的另一个选项是要求序列对象提前(在开始批量复制之前)生成所需数量的 ID,并提供这些 ID 以及来自客户端的其余行数据。设置批量复制的相应选项,以便插入提供的ID。
服务器是否启用了自动增量?
@Arphile Autoincrement 未在该列上启用 - 它使用的是序列
@VladimirBaranov 我会看看列映射选项。知道如何提前创建一组 ID 吗?
您必须对SqlBulkCopy
的任何重要使用使用显式列映射,否则它将按序号映射列(即表中列的物理位置),这几乎没有帮助。在这种情况下,您需要为所有列 除了 ID 添加映射,这很容易完成 (foreach (Column c in table.Columns) if ("ID".Equals(c.ColumnName)) continue; bulk.ColumnMappings.Add(c.ColumnName, c.ColumnName);
)。
【参考方案1】:
如何通过SqlCommand.ExecuteScalar()
向 SQL Server 询问当前序列值。将此 SQL 语句用作命令的输入:
SELECT current_value
FROM sys.sequences
WHERE OBJECT_ID = OBJECT_ID(N'dbo.MyTableId');
然后将列属性AutoIncrementSeed
设置为上一个值加一:
// ... code to get current sequence value
string sqlText = <above sql goes here>;
SqlCommand getSeqValue = new(sqlText, your_connection);
long currentSequenceValue = (long)getSeqValue.ExecuteScalar();
// Construct DataTable structure
// maybe replacing adapter.Fill(table);
// with
//adapter.FillSchema(table,SchemaType.Source);
// tell table to start ID on current sequence value + 1 (or AutoIncrementStep)
table.Columns["Id"].AutoIncrement = true;
table.Columns["Id"].AutoIncrementSeed = currentSequenceValue + 1;
// prepare things and bulk insert
只是一个想法,尚未测试。 :/
【讨论】:
以上是关于使用序列设置主 ID 时如何将数据批量插入表中的主要内容,如果未能解决你的问题,请参考以下文章