如何在使用SqlBulkCopy时检索服务器生成的标识值

我知道我可以通过不指定此处提到的SqlBulkCopyOptions.KeepIdentity来使用标识列批量插入到我的表中。

我希望能够获得服务器生成的标识值并将它们放在我的数据表中,甚至是列表中。 我看到这篇文章,但我希望我的代码是通用的,我的所有表中都没有版本列。 任何建议都非常感谢。 这是我的代码:

 public void BulkInsert(DataTable dataTable, string DestinationTbl, int batchSize) { // Get the DataTable DataTable dtInsertRows = dataTable; using (SqlBulkCopy sbc = new SqlBulkCopy(sConnectStr)) { sbc.DestinationTableName = DestinationTbl; // Number of records to be processed in one go sbc.BatchSize = batchSize; // Add your column mappings here foreach (DataColumn dCol in dtInsertRows.Columns) { sbc.ColumnMappings.Add(dCol.ColumnName, dCol.ColumnName); } // Finally write to server sbc.WriteToServer(dtInsertRows); } } 

AFAIK,你不能。

获取标识字段值的唯一方法(我知道)是在逐行插入时使用SCOPE_IDENTITY() ; 或者在插入整个集合时使用OUTPUT方法。

“最简单”的方法可能是你将SqlBulkCopy记录在表中,然后再将它们取回。 问题可能是很难正确(并且快速)从服务器再次获取这些行。 (例如,使用IN (guid1, guid2, .., guid999998, guid999999) =的WHERE子句会相当丑陋(而且很慢)

我假设性能是一个问题,因为你已经在使用SqlBulkCopy,所以我建议采用OUTPUT方法,在这种情况下,你首先需要一个临时表到SqlBulkCopy你的记录。所述表应该包括某种批量标识符(GUID?)允许多个胎面并排运行。 您需要一个存储过程来INSERT

OUTPUT inserted.* SELECT

将staging-table中的数据INSERT

OUTPUT inserted.* SELECT

到实际的目标表中,并再次清理staging表。 然后,来自所述程序的returend记录集将以1:1匹配到负责填充临时表的原始数据集,但是当然你不应该依赖它的顺序。 换句话说:您的下一个挑战是将返回的标识字段与应用程序中的原始记录进行匹配。

考虑到这一点,我会说在所有情况下 – 除了逐行和SCOPY_IDENTITY()方法,这将是狗慢 – 你需要(或添加)一个’键’将您生成的ID链接回原始数据的数据= /

您可以通过deroby执行上述类似的方法,而不是通过WHERE IN (guid1, etc...将它们检索回来WHERE IN (guid1, etc...根据它们的顺序将它们匹配回内存中插入的行。

因此,我建议在表上添加一列以将该行与SqlBulkCopy事务匹配,然后执行以下操作以将生成的ID与您刚刚插入的行的内存集合进行匹配。

  • 创建一个新的Guid,并将此值设置为批量复制映射到新列的所有行

  • 运行BulkCopy对象的WritToServer方法

  • 检索具有相同密钥的所有行

  • 通过这个列表迭代它们将按照它们被添加的顺序排列,它们将与行的内存集合中的顺序相同,这样您就可以知道每个项目生成的id。

这将为您提供比为每个单独的行提供唯一键更好的性能。 因此,在批量插入数据表后,您可以执行类似这样的操作(在我的示例中,我将有一个对象列表,我将从中创建数据表,然后将生成的ID映射回它们)

 List myCollection = new List Guid identifierKey = Guid.NewGuid(); //Do your bulk insert where all the rows inserted have the identifierKey //set on the new column. In this example you would create a data table based //off the myCollection object. //Identifier is a column specifically for matching a group of rows to a sql //bulk copy command var myAddedRows = myDbContext.DatastoreRows.AsNoTracking() .Where(d => d.Identifier == identiferKey) .ToList(); for (int i = 0; i < myAddedRows.Count ; i++) { var savedRow = myAddedRows[i]; var inMemoryRow = myCollection[i]; int generatedId = savedRow.Id; //Now you know the generatedId for the in memory object you could set a // a property on it to store the value inMemoryRow.GeneratedId = generatedId; }