更新:Here is my solution
我有一个表定义为:
CREATE TABLE [dbo].[csvrf_References]
(
[Ident] [int] IDENTITY(1,1) NOT NULL,
[ReferenceID] [uniqueidentifier] NOT NULL DEFAULT (newsequentialid()),
[Type] [nvarchar](255) NOT NULL,
[Location] [nvarchar](1000) NULL,
[Description] [nvarchar](2000) NULL,
[CreatedOn] [datetime] NOT NULL DEFAULT (getdate()),
[LastUpdatedOn] [datetime] NOT NULL DEFAULT (getdate()),
[LastUpdatedUser] [nvarchar](100) NOT NULL DEFAULT (suser_sname()),
CONSTRAINT [PK_References] PRIMARY KEY NONCLUSTERED ([ReferenceID] ASC)
) ON [PRIMARY]
我有一个
DataTable
具有与表列名称和数据类型匹配的列。 DataTable
填写的是DBNull.Value
在 CreatedOn
, LastUpdatedOn
和 LastUpdatedUser
. ReferenceID
已经生成。当我调用以下代码时,出现以下错误。代码:
SqlBulkCopy bulkCopy = new SqlBulkCopy(conn, SqlBulkCopyOptions.Default, bulkCopyTran);
bulkCopy.DestinationTableName = table.TableName;
bulkCopy.ColumnMappings.Clear();
foreach (DataColumn col in table.Columns) bulkCopy.ColumnMappings.Add(col.ColumnName, col.ColumnName);
bulkCopy.WriteToServer(table);
错误:
Error trying to BulkCopy table csvrf_References
System.InvalidOperationException: Column 'CreatedOn' does not allow DBNull.Value.
at System.Data.SqlClient.SqlBulkCopy.ConvertValue(Object value, _SqlMetaData metadata, Boolean isNull, Boolean& isSqlType, Boolean& coercedToDataFeed)
我已经看遍了,我似乎无法找到答案。
SqlBulkCopy
class 似乎不尊重默认值,即使它说它确实如此。我在这里做错了什么?
最佳答案
对于第 1 部分,“具有默认值的 NOT NULL 字段”,您首先不应发送该字段。它不应该被映射。无需为此更改该字段以接受 NULL。
对于第 2 部分,“带有 DEFAULT 的 NULL 字段”,只要您没有将 SqlBulkCopyOptions 设置为 KeepNulls
,就可以在传入 DbNull.Value 时获取默认值。 , 否则它会插入一个实际的数据库 NULL
.
由于 KeepNulls
的 SqlBulkCopyOption 存在一些混淆,我们来看看它的定义:
Preserve null values in the destination table regardless of the settings for default values. When not specified, null values are replaced by default values where applicable.
这意味着 DataColumn 设置为
DbNull.Value
将作为数据库插入 NULL
,即使该列具有 DEFAULT CONSTRAINT,如果 KeepNulls
选项被指定。它没有在您的代码中指定。这导致了第二部分 DbNull.Value
在适用的情况下,值被替换为“默认值”。这里的“适用”意味着该列上定义了一个 DEFAULT CONSTRAINT。因此,当存在默认约束时,非 DbNull.Value
值将按原样发送,而 DbNull.Value
应该转换为 SQL 关键字 DEFAULT
.该关键字在 INSERT 语句中被解释为采用 DEFAULT 约束的值。当然,也有可能是SqlBulkCopy
,如果发出单独的 INSERT 语句,如果该行设置为 NULL,则可以简单地将该字段排除在列列表之外,这将采用默认值。在任何一种情况下,最终结果都是它按您的预期工作。我的测试表明它确实以这种方式工作。明确区分:
NOT NULL
并在其上定义了 DEFAULT CONSTRAINT,您的选择是:DbNull.Value
ColumnMappings
全收藏ColumnMappings
集合,以便您可以将该字段排除在映射之外。 KeepNulls
不会改变上述行为。 NULL
并在其上定义了 DEFAULT CONSTRAINT,您的选择是:ColumnMappings
全收藏ColumnMappings
集合,以便您可以将该字段排除在映射之外。 DbNull.Value
的值的字段,在这种情况下,它将被设置为这个值,而不是选择默认值 DbNull.Value
在现场传递,在这种情况下,效果取决于是否SqlBulkCopyOptions
正在传入,已设置为KeepNulls
:KeepNulls
未设置将取默认值 KeepNulls
设置将保留该字段设置为 NULL
下面是一个简单的测试,看看
DEFAULT
关键词作品:--DROP TABLE ##DefaultTest;
CREATE TABLE ##DefaultTest
(
Col1 INT,
[CreatedOn] [datetime] NOT NULL DEFAULT (GETDATE()),
[LastUpdatedOn] [datetime] NULL DEFAULT (GETDATE())
);
INSERT INTO ##DefaultTest (Col1, CreatedOn) VALUES (1, DEFAULT);
INSERT INTO ##DefaultTest (Col1, LastUpdatedOn) VALUES (2, DEFAULT);
INSERT INTO ##DefaultTest (Col1, LastUpdatedOn) VALUES (3, NULL);
INSERT INTO ##DefaultTest (Col1, LastUpdatedOn) VALUES (4, '3333-11-22');
SELECT * FROM ##DefaultTest ORDER BY Col1 ASC;
结果:
Col1 CreatedOn LastUpdatedOn
1 2014-11-20 12:34:31.610 2014-11-20 12:34:31.610
2 2014-11-20 12:34:31.610 2014-11-20 12:34:31.610
3 2014-11-20 12:34:31.610 NULL
4 2014-11-20 12:34:31.613 3333-11-22 00:00:00.000
关于c# - 当源 DataTable 行具有 DBNull.Value 时,SqlBulkCopy 到默认列值失败的表中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27027013/