【发布时间】:2014-03-04 00:08:02
【问题描述】:
在我们的数据库表中,我们使用两个唯一的非聚集索引来创建跨四个字段的唯一约束。我们使用两个,因为其中一个字段,ZipCode 是一个可为空的字段。如果表中存在一条记录,该记录具有 ZipCode 的 null 条目,我们不希望出现新记录与其他三个字段匹配但已定义 ZipCode 并被添加(反之亦然)的情况。
问题是似乎使用SqlBulkCopy 没有强制执行任何约束,因为您可以添加任何您喜欢的记录,而不管表上已有什么。
在另一个程序中,我们使用Entity Framework,因为我们加载的数据量要少得多。使用 EF,这些约束可以完美地工作(它们目前正在生产中)。但是,使用 SqlBulkCopy 似乎它们被完全忽略了。
T-SQL
CREATE UNIQUE NONCLUSTERED INDEX [UQ_ChannelStateEndDateZipCodeNOTNULL] ON [dbo].[ZipCodeTerritory]
(
[ChannelCode] ASC,
[StateCode] ASC,
[ZipCode] ASC,
[EndDate] ASC
)
WHERE ([ZipCode] IS NOT NULL)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO
CREATE UNIQUE NONCLUSTERED INDEX [UQ_ChannelStateEndDateZipCodeISNULL] ON [dbo].[ZipCodeTerritory]
(
[ChannelCode] ASC,
[StateCode] ASC,
[ZipCode] ASC,
[EndDate] ASC
)
WHERE ([ZipCode] IS NULL)
WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, SORT_IN_TEMPDB = OFF, IGNORE_DUP_KEY = OFF, DROP_EXISTING = OFF, ONLINE = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, FILLFACTOR = 90) ON [PRIMARY]
GO
C#
Dictionary<DataRow, string> faultyRows = new Dictionary<DataRow, string>();
using (SqlConnection connection = new SqlConnection(connString))
{
//Open Database connection
connection.Open();
//Create transaction objects
SqlTransaction transaction = connection.BeginTransaction();
SqlBulkCopy bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.CheckConstraints, transaction);
bulkCopy.DestinationTableName = "ZipCodeTerritory";
//Load data and initialize datatable
DataTable dataTable = LoadData(inserts);
IDataReader reader = dataTable.CreateDataReader();
DataTable dataSchema = reader.GetSchemaTable();
DataTable tmpDataTable = InitializeStructure();
//Create array to hold data being transfered into tmpDataTable
object[] values = new object[reader.FieldCount];
while (reader.Read())
{
//Clear temp table for single-record use
tmpDataTable.Rows.Clear();
//Get data for current row
reader.GetValues(values);
//Load values into the temp table
tmpDataTable.LoadDataRow(values, true);
//Load one record at a time
try
{
bulkCopy.WriteToServer(tmpDataTable);
transaction.Commit();
}
catch (Exception ex)
{
faultyRows.Add(tmpDataTable.Rows[0], ex.Message);
}
}
}
编辑
我发现如果定义了ZipCode 字段,则实际上会强制执行此约束。 ChannelCode、StateCode、ZipCode、EndDate 字段的任何匹配都将导致 SqlException 具有以下 Message 属性(从我刚刚运行的特定文本中提取):
Cannot insert duplicate key row in object 'dbo.ZipCodeTerritory' with unique index 'UQ_ChannelStateEndDateZipCodeNOTNULL'. The duplicate key value is (9, WA , 98102 , 9999-12-31)
但是,这是我唯一一次可以触发我们的两个约束之一。
【问题讨论】:
-
切换到
bcp命令可行吗?如果您可以使用它,您可以将CHECK_CONSTRAINTS选项放在它上面,否则它将忽略约束,就像SqlBulkCopy -
SqlBulkCopy 有疯狂的(!)默认值。见副本。例如,它将禁用现有的外键。这是一个 DDL 操作,在没有警告的情况下隐式执行。
-
@SaUce: 怎么重复??我在构造函数中设置了
SqlBulkCopyOptions,与该问题的答案相同。我们也没有任何触发器。 -
@SaUce 我也不确定“切换到
bcp命令”是什么意思 -
我删除了重复的标志,起初我没有注意到
SqlBulkCopyOptions必须向右滚动。通过切换,我的意思是编写将执行 BCP 命令的 SP,您需要做的就是传递所需的属性。
标签: c# sql sqlbulkcopy