How can I set column type when using SqlBulkCopy to insert into a sql_variant column

ado.net datatable sqlbulkcopy sql-server sql-variant

Question

I'm using SqlBulkCopy to insert/update from a .net DataTable object to a SQL Server table that includes a sql_variant column. However SqlBulkCopy insists on storing DateTime values put into that column as sql type 'datetime' when what I need is 'datetime2'.

My DataTable is defined like this:

DataTable dataTable = new DataTable();
dataTable.Columns.Add(new DataColumn("VariantValue", typeof(object))); //this represents my sql_variant column

Then I throw some data in there that requires a 'datetime2' to store.

DataRow row = dataTable.NewRow();
row[0] = DateTime.MinValue;
dataTable.Rows.Add(row);

And then I use SqlBulkCopy to get that data into Sql Server:

using (SqlBulkCopy bulk = new SqlBulkCopy(myConnection))
{
     bulk.DestinationTableName = "tblDestination";     
     bulk.WriteToServer(dataTable);     
}

My bulk copy will fail if a DateTime value is present in the data table that falls outside the range of the sql 'datetime' type (such as '1/1/0001'). That's why the column needs to be of type 'datetime2'.

When you're writing normal insert statements that insert into a sql_variant column you can control what the type of the variant column is by using CAST or CONVERT. For example:

insert into [tblDestination] (VariantValue) values (CAST('1/1/0001' AS datetime2))

Then if you were to display the actual type of the variant column like this:

SELECT SQL_VARIANT_PROPERTY(VariantValue,'BaseType') AS basetype FROM test

You'd see that indeed it is being stored as a 'datetime2'.

But I'm using SqlBulkCopy and, as far as I know, there's no place to tell it that .net DateTime objects should be stored in columns of type 'datetime2' and not 'datetime'. There's no place on the DataTable object, that I know of, to declare this either. Can anyone help me figure out how to get this to happen?

Accepted Answer

According to the MSDN page for SqlBulkCopy (under "Remarks"):

SqlBulkCopy will fail when bulk loading a DataTable column of type SqlDateTime into a SQL Server column whose type is one of the date/time types added in SQL Server 2008.

So, SqlBulkCopy won't be able to handle DateTime2 values. Instead, I'd suggest one of two options:

  1. Insert each row individually (i.e. use a foreach on your DataTable), handling the datatype there. (It might help to use a stored proc to wrap the insert and utilize SqlCommand.Parameters to type the data for the insert.)
  2. Bulk insert into a temp table of strings, then transfer the data to your primary table (converting data types as necessary) in SQL. (which I think will get unnecessarily complicated, but you may be able to eek out some performance for large datasets)


Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Is this KB legal? Yes, learn why