使用SqlBulkCopy将DEFAULT关键字传递给不可为空的列

时间:2017-05-29 09:52:58

标签: c# sql-server sqlbulkcopy

有没有办法从IDataReader将DEFAULT关键字传递给SqlBulkCopy?
基本上相当于

INSERT INTO MyTable(NonNullableWithDefault)
VALUES (DEFAULT)

在我的应用程序中,目标表具有不可为空的列,并且对它们有默认约束 要上传的部分数据包含这些列的值,有些则没有 对于没有值的行(DBNull),它应该使用默认约束。

this answer中所述,SqlBulkCopy要求您根本不传递ColumnMapping或发送值。

替代方案我正在考虑

  • 拆分数据以传入不同的列映射(复杂)
  • 检查数据库的默认值并将其填入datareader(慢速)
  • 以某种方式创建没有约束的单独转储表(复杂,可能很慢)

我不能成为第一个遇到这个问题的人 人们在这种情况下使用了什么?

更新

经过多次摆弄后,我现在用一个查询获取整个数据库结构,然后将该数据集传递给我的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);
}

优点:

  • 不可为空的默认值解决方法
  • 清除验证消息(如最大长度)
  • 处理列名称大小写匹配

缺点

  • 解析默认值字符串
  • 无法解析sql端默认值(如sprocs)

1 个答案:

答案 0 :(得分:1)

  

有没有办法从IDataReader将DEFAULT关键字传递给SqlBulkCopy?

不幸的是,没有。 :-(如果列为NOT NULL并且您的批量插入映射到该列,则每行必须具有该列的值。

背景:在TDS级别,通过发送使用仅外部工具语法后跟INSERT statement包含列元数据然后行的SQL TDS structures来完成批量插入数据。这些都没有提供说明方式&#34;如果NULL值在非NULL能力列中,请将NULL视为DEFAULT。&# 34;

  

人们在这种情况下使用了什么?

嗯......当感觉应该有内置的,简单的解决方案而且所有选项都很痛苦时,它会令人沮丧。 : - /如果不了解您的情况,很难知道推荐哪个选项。

另外一个选项:占位符值方法。在插入之前,替换应该默认的&#34; NULL&#34;具有占位符值。然后,插入后,运行更新以使用数据库生成的默认值(例如UPDATE ... SET Col1 = DEFAULT WHERE Col1 = *placeholder*)替换占位符。您的应用程序必须知道哪些非可空列具有默认值,但不必知道如何计算默认值。我不关心它,因为它使用所谓的魔术数字 - 但它是一种选择。