gpt4 book ai didi

c# - 使用 SqlBulkCopy 时未(始终)强制执行约束

转载 作者:太空宇宙 更新时间:2023-11-03 16:00:39 26 4
gpt4 key购买 nike

在我们的数据库表上,我们使用两个唯一的非聚集索引来创建跨四个字段的唯一约束。我们使用两个,因为其中一个字段 ZipCode 是一个可为空的字段。如果表中存在一条包含 ZipCodenull 条目的记录,我们不希望新记录与其他三个字段匹配但具有已定义的 >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 字段,这个约束实际上会被强制执行。 ChannelCodeStateCodeZipCodeEndDate 字段的任何匹配都将导致 SqlException 具有以下 Message 属性(从我刚刚运行的特定文本中提取):

无法在具有唯一索引“UQ_ChannelStateEndDateZipCodeNOTNULL”的对象“dbo.ZipCodeTerritory”中插入重复键行。重复键值是 (9, WA , 98102 , 9999-12-31)

但是,这是我唯一一次可以触发两个约束之一。

最佳答案

发生这种情况是因为我使用了将数据从模型对象(我仍在某些地方使用 Entity Framework )传输到 DataRow 的方法。下面是我现在使用的方法。在我修复之前,当 null 时,ZipCode 字段被作为空字符串放入 DataRow 列中。由于这在技术上不是空字段,因此未触发约束。

    private static DataTable LoadData(List<ZipCodeTerritory>zipCodeList, bool update = false)
{
DataTable dataTable = InitializeStructure();

foreach (var zipcode in zipCodeList)
{
DataRow row = dataTable.NewRow();

try
{
row[0] = zipcode.ChannelCode.Trim();
row[1] = zipcode.DrmTerrDesc.Trim();
row[2] = zipcode.IndDistrnId.Trim();
row[3] = zipcode.StateCode.Trim();
row[4] = (string.IsNullOrWhiteSpace(zipcode.ZipCode) ? null : zipcode.ZipCode.Trim());
row[5] = zipcode.EndDate.Date;
row[6] = zipcode.EffectiveDate.Date;
row[7] = zipcode.LastUpdateId;
row[8] = DateTime.Now.Date;
row[10] = zipcode.ErrorCodes;
row[11] = zipcode.Status;

//Add the Id column if we're doing an update
if(update) row[9] = zipcode.Id;
}
catch (Exception ex)
{

}

dataTable.Rows.Add(row);
}

return dataTable;
}

关于c# - 使用 SqlBulkCopy 时未(始终)强制执行约束,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21613191/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com