Я использую c # с .NET 4.5.2, отправляю на SQL Server 2017 14.0.1000.169
В моей базе данных есть таблица с полем DateAdded типа DateTimeOffset
.
Я пытаюсь выполнить BulkCopy с помощью следующего кода:
private Maybe BulkCopy(SqlSchemaTable table, System.Data.DataTable dt, bool identityInsertOn)
{
try
{
var options = SqlBulkCopyOptions.TableLock | SqlBulkCopyOptions.FireTriggers | SqlBulkCopyOptions.UseInternalTransaction; // | SqlBulkCopyOptions.CheckConstraints; // Tried CheckConstraints, but it didn't change anything.
if (identityInsertOn) options |= SqlBulkCopyOptions.KeepIdentity;
using (var conn = new SqlConnection(_connString))
using (var bulkCopy = new SqlBulkCopy(conn, options, null))
{
bulkCopy.DestinationTableName = table.TableName;
dt.Columns.Cast<System.Data.DataColumn>().ToList()
.ForEach(x => bulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping(x.ColumnName, x.ColumnName)));
try
{
conn.Open();
bulkCopy.WriteToServer(dt);
}
catch (Exception ex)
{
return Maybe.Failure(ex);
}
}
}
catch (Exception ex)
{
return Maybe.Failure(ex);
}
return Maybe.Success();
}
Я знаю две возможные причины ошибки does not allow DBNull
:
- Столбцы расположены в неправильном порядке, что можно решить, разместив их в том же порядке, что и их порядковый номер в базе данных, или выполнив сопоставление столбцов.
- KeepNulls включен, и
DBNull.Value
(или null
?) Установлены в DataTable.
Но я правильно сопоставляю карты и НЕ настраиваю KeepNulls.
Пока я получаю сообщение об ошибке:
Столбец DateAdded не допускает DBNull.Value
РЕДАКТИРОВАТЬ Я также пытался просто НЕ УСТАНОВИТЬ что-либо, включая null
, DBNull.Value
и DefaultValue
... просто буквально вообще не устанавливая этот столбец.
Кроме того, если я удаляю столбец DateAdded из DataTable, он работает. Но я этого не хочу. Возможно, из 100 000 записей 20 имеют данные. Поэтому в моих пакетах по 500 иногда ни один не имеет данных в поле DateAdded, иногда один или два имеют данные.
Так что я хотел бы сохранить столбец в моей DataTable, но позволить ему использовать DefaultValue.
Последнее замечание: я чередовал установку значения DataColumn на DBNull.Value
против dt.Columns[x.ColumnName].DefaultValue
. Оба способа дают одну и ту же ошибку.
Редактировать 2
Это код, который я использую для заполнения данных в моей таблице данных:
foreach (var column in table)
{
System.Data.DataRow newRow = dt.NewRow();
foreach (var field in column)
{
if (!IsNull(field.Value) && !IsEmptyDateOrNumber(field.ColumnType, field.Value))
{
// For DateAdded, this is not hit on the first batch, though there are columns Before and After DateAdded on the same row which do have value.
// But it WILL be hit once or twice a few batches later. So I don't want to completely remove the definition from the DataTable.
newRow[field.ColumnName] = field.Value;
}
else
{
// newRow[field.ColumnName] = dt.Columns[field.ColumnName].DefaultValue;
// newRow[field.ColumnName] = DBNull.Value;
// dt.Columns[field.ColumnName].AllowDBNull = true;
}
}
dt.Rows.Add(newRow);
}
IsNull()
возвращает TRUE
, если значение null
или строка "null"
, как требуется для моих бизнес-требований.
IsEmptyDateOrNumber()
вернет TRUE
, если поле числового типа или типа даты, а значение равно нулю или пусто ""
. Поскольку пустое значение допустимо для многих строковых полей, оно никогда не является допустимым числовым значением.
Условие для присвоения полю значения задается ровно 0 процентов времени для этого конкретного столбца. Таким образом, ничего не установлено.