Есть ли способ передать ключевое слово DEFAULT в SqlBulkCopy из IDataReader?
В основном эквивалент
INSERT INTO MyTable(NonNullableWithDefault)
VALUES (DEFAULT)
В моем приложении целевые таблицы имеют столбцы с нулевыми значениями с ограничениями по умолчанию для них.
Некоторые данные для загрузки имеют значения для этих столбцов, некоторые - нет.
Для строк, где нет значения (DBNull), он должен использовать ограничение по умолчанию.
Как отмечено в этом ответе, SqlBulkCopy либо ожидает, что вы вообще не пройдете в ColumnMapping или не отправите значение.
Альтернативы, которые я рассматриваю
Я не могу быть первым человеком с этой проблемой.
Что люди используют в таком сценарии?
ОБНОВИТЬ
После многократной игры я теперь получаю всю структуру базы данных с одним запросом, а затем передаю этот набор данных своим datareaders.
SELECT
columns.TABLE_SCHEMA schemaName
, columns.TABLE_NAME tableName
, columns.TABLE_SCHEMA + '.' + columns.TABLE_NAME fullTableName
, columns.COLUMN_NAME columnName
, columns.DATA_TYPE dataType
, ISNULL(columns.CHARACTER_MAXIMUM_LENGTH, -1) charlength
, columns.COLUMN_DEFAULT defaultValue
, columns.ORDINAL_POSITION ordinalPosition
FROM
information_schema.columns columns
Разбор строки значений по умолчанию не очень хорош и, скорее всего, не подходит для расширенных случаев. Однако в нашем случае он охватывает все базы.
private object ParseDefault(DataRow row)
{
if(row.IsNull("defaultValue")) return null;
var value = row.Field<string>("defaultValue");
if (value == "(getdate())")
{
return DateTime.UtcNow;
}
var type = GetTypeForName(row.Field<string>("dataType"));
return ParseCell(value.Trim('(', ')'), type);
}
private static object ParseCell(string value, Type info)
{
if (value.Equals("NULL", StringComparison.OrdinalIgnoreCase))
{
return DBNull.Value;
}
int intValue;
if (info == typeof(bool) && int.TryParse(value, out intValue))
{
return intValue == 1;
}
var foo = TypeDescriptor.GetConverter(info);
return foo.ConvertFromInvariantString(value);
}
Преимущества:
Недостатки
Есть ли способ передать ключевое слово DEFAULT в SqlBulkCopy из IDataReader?
К сожалению нет. :-( Если столбец NOT NULL
и ваша массивная вставка сопоставляется с ним, каждая строка должна иметь значение для этого столбца.
Справочная информация. На уровне TDS объемная вставка выполняется путем отправки INSERT
SQL INSERT
написанной с использованием только синтаксиса внешних инструментов, за которым следуют структуры TDS, содержащие метаданные столбца, а затем данные строки. Ни один из них не обеспечивает способ сказать «если NULL
значение в не- NULL
умелым столбце, относятся к NULL
в качестве DEFAULT
.»
Что люди используют в таком сценарии?
Хм ... это расстраивает, когда кажется, что должно быть встроенное, простое решение, и вместо этого все варианты болезненны. : - / Не зная больше о вашей ситуации, трудно понять, какой вариант рекомендовать.
Еще один вариант: подход с учетом стоимости. Перед вставкой замените значение « NULL
s, которое должно быть по умолчанию», с использованием значения-заполнителя. Затем, после вставки, запустите обновление (-ы), чтобы заменить заполнители (-и) стандартными значениями базы данных (например, UPDATE ... SET Col1 = DEFAULT WHERE Col1 = *placeholder*
). Ваше приложение должно было бы знать, какие столбцы с нулевым значением имеют значения по умолчанию, но не должны знать, как вычислить значения по умолчанию. Меня это не волнует, потому что он использует так называемые магические числа, но это вариант.