如何使用SqlBulkCopy获取插入数据的id?为了形成子表,需要此id。我看到了在msdn上的示例(http://msdn.microsoft.com/en-us/library/ac44f8yy(v=vs.110).aspx),它能够实现此功能。但是该示例未提及如何获取id。以下是c#程序代码。
如何使用SqlBulkCopy获取插入数据的id?为了形成子表,需要此id。我看到了在msdn上的示例(http://msdn.microsoft.com/en-us/library/ac44f8yy(v=vs.110).aspx),它能够实现此功能。但是该示例未提及如何获取id。以下是c#程序代码。
不可能。您必须使用传统的INSERT
语句,使用scope_identity()
或使用OUTPUT
子句来获取ID的值-假设ID来自IDENTITY
列类型。
SqlBulkCopy
不适用于事务性插入。它旨在在服务器之间复制大量数据。
SqlBulkCopy
是有效的。但是,仍然有比使用 SCOPE_IDENTITY()
的单行插入更好的方法来插入多行。 - Solomon RutzkySqlBulkCopy
可能不是必需的,但说它无效/不正确是不公平的。如果您不需要SqlBulkCopy
的任何特殊功能,则将整个数据集作为TVP或至少作为XML传递,并通过OUTPUT子句(我的第二个答案)捕获所有新ID,是批量操作的首选方法。 - Solomon Rutzky如果您正在插入多行,但不需要 SqlBulkCopy 的任何特殊功能,则应考虑使用 Table-Valued Parameters(TVPs)。您可以创建一个接受 TVP 并返回结果集的存储过程。存储过程的主体应该是以下内容:
CREATE PROCEDURE SchemaName.StoredProcName
(
@Rows SchemaName.TableTypeName READONLY
)
AS
SET NOCOUNT ON;
INSERT INTO SchemaName.ImportTable (Field1, ..., FieldN)
OUTPUT INSERTED.ID, INSERTED.IdentifyingField1, ..., INSERTED.IdentifyingFieldN
SELECT Field1, ..., FieldN
FROM @Rows;
一种获得ID的方法是通过使用以下方式将其强制插入到您的标识中:
SET IDENTITY_INSERT (Transact-SQL)
use database
go
set identity_insert myDatabase.mySchema.MyTable on
go
...
set identity_insert myDatabase.mySchema.MyTable off
go
虽然这些几乎不适用于客户端代码进程。
此外,我从未尝试过在客户端代码(C#,VB,任何其他语言)中直接执行此类过程。
如@CamBruce所述,这些是针对批处理或其他用途而设计的。也许您最好使用INSERT ... SELECT ...
语句,如您问题中的参考所述:
{{link1:SqlBulkCopy.WriteToServer Method (DataRow[])}}
重要提示:
如果源表和目标表位于同一SQL Server实例中,则使用Transact-SQL INSERT ... SELECT语句复制数据更容易且更快。
假设以下两个陈述对您的特定情况是正确的:
那么就有一个选项。正如其他人所述,SqlBulkCopy用于批处理/远程处理,因此您无法直接访问它实际执行INSERT的会话。因此,您需要一个完全独立的机制来捕获值。触发器就是这样的机制。您可以使用触发器将新ID以及标识字段插入另一个表中,在SqlBulkCopy完成后可以从中读取。
创建一个表来暂时存储新 ID。如下所示,请注意所有字段都应为 NOT NULL,因为任何可以包含 NULL 的字段都不能成为 PK 的一部分,因此在此处不适合您的需求。CREATE TABLE SchemaName.TempIDs
(
ID INT NOT NULL,
IdentifyingField1 DataType NOT NULL,
....
IdentifyingFieldN DataType NOT NULL,
CreatedDate DATETIME NOT NULL
CONSTRAINT [DF_TempIDs_CreatedDate] DEFAULT (GETDATE())
);
CREATE TRIGGER SchemaName.ImportTable_CaptureIDs
ON SchemaName.ImportTable
AFTER INSERT
AS
SET NOCOUNT ON;
INSERT INTO SchemaName.TempIDs
(ID, IdentifyingField1, ..., IdentifyingFieldN)
SELECT ID, IdentifyingField1, ..., IdentifyingFieldN
FROM INSERTED;
DELETE FROM SchemaName.TempIDs;
。当然,您需要考虑到流程可能会失败,并根据应用程序代码编写的方式来看,如果您可以再次将子数据加载到内存中以插入到相关表中,则不需要调用删除操作。在这种情况下,您需要先检查是否有记录在 SchemaName.TempIDs
中,如果是,则处理它们,然后再删除它们。SqlBulkCopy
获得的任何性能增益可能会导致净损失。 - Cam BruceSqlBulkCopy
旨在高效/批量插入数据,而不仅仅是从服务器到服务器,正如您在答案中所述。如果您查看问题中的链接,他正在传递一个DataRow
数组,因此来自应用程序的多个行。这是SqlBulkCopy
的几个预期用途之一。一个简单的触发器插入到没有争用的表中将几乎没有影响。由于插入集比您建议的单行插入更快,因此可能您的建议实际上比我的更慢。 - Solomon RutzkySqlBulkCopy
的可接受和预期使用方式,而触发器对性能的影响可以忽略不计。相比之下,即使在事务中进行单行插入,也会比使用SCOPE_IDENTITY()
慢得多/更糟糕。 - Solomon Rutzky
SqlBulkCopy
有特定的原因吗?它是否具有您需要的特定功能,还是您仅仅想在单个调用中插入多个记录? - Solomon RutzkySqlBulkCopy
的特定功能(例如BulkCopyOptions
等),那么我关于触发器的第一个答案是合适的。否则,对于多行操作,我的另一个有关表值参数的答案是首选方法(从SQL Server 2008开始)。 - Solomon Rutzky