问题描述
我正在尝试批量插入对象列表(列表发票)。有时,它会失败并引发异常。但是,我想知道哪些行失败。这样,我可以通过省略那些行来重做批量插入。我可以这样做吗?
解决方法
这是使用 Bulk 操作的缺点之一,反馈是全有还是全无。
当使用 Bulk 操作时,我们通常会绕过通常对每一行进行的验证和验证,这是提高性能的主要折衷方案。不能同时拥有。
SqlBulkCopy
专门设计用于清理数据
因此,在尝试复制数据之前,您应该首先考虑如何清理数据,因为它可能采用多种形式,所以我们不能涵盖本文中的所有内容。
最常见的可能失败的约束是使用null值(在不支持null的字段中)和外键(null或不匹配)。 通常,我们可以预先验证批量数据中是否存在不存在的空值和键,只需查询您的批量集以在不支持空值的列中查找具有空值的行。您还可以查询目标数据库中外键列中的值尚不存在的任何行。
您尚未提供有关内存中数据结构的任何详细信息,因此这是基于空值进行过滤的抽象示例:
DataTable bulkData; ... load the data // Columns that do not support nulls: Col1,Col3 DataRow[] dataWithNulls = bulkData.Select("[Col1] IS NULL OR [Col3] IS NULL"); // Get only rows that do not have nulls DataRow[] bulkDataSanitised = bulkData.Select("[Col1] IS NOT NULL AND [Col3] IS NOT NULL");
要对丢失的FK进行类似的查询,您必须首先获取FK值的不同列表,然后查询数据库以查找不匹配的那些值,然后可以过滤出丢失FK的行。值。
如果您是从通用的角度来解决这个问题,那么您就事先不知道表模式,那么在这种情况下,我们通常遵循的概念性过程是将批量设置分解为较小的块并执行那些块
在您的界面中,允许用户指定起始行和要复制的行数(如果可行),请从源集中删除行。如果失败,请要求用户再试一次。
您的最后一个选择是根本不批量执行此操作!您仍然可以使用SqlBulkCopy
,但是一次只能发送一行,这样您就可以处理每行失败的情况。
如果出于性能原因而使用SqlBulkCopy
,则(当然,还有其他非性能原因会使用SqlBulkCopy),那么,如果您使用此方法,则会失去所有性能,但是如果失败的频率较低,则可以先尝试完全批量操作,然后在失败时逐行执行。
有关代码项目Retrieving failed records after an SqlBulkCopy exception的这篇文章介绍了一种解决方案,可以帮助您解决此问题,但是您可以很轻松地提出自己的实现方案。
您可以结合使用这两种方法,首先尝试全部操作,然后在失败时将表拆分为失败的多个子表,然后继续递归尝试并再拆分表,直到达到1行的表。这类似于用户可以手动执行相同的消除过程,并且从一开始就逐行进行操作仍将保留一些性能优势,但这仅适用于故障率相对较低的大型设备。 >