SqlBulkCopy Bug Workaround
We are using SqlBulkCopy to import large xml documents into a database. However, we encountered a “minor” bug in the .Net Framework related to table naming. It turns out that if you have a dot “.” in the table name, SqlBulkCopy doesn’t work. The problem has been reported and a KB article is available, but without a workaround besides renaming the table. Our problem wasn’t with the actual name of the table(s), but with the name of the schema. The schema naming convention used in that specific database is [CompanyName.Project].TableName.
The following code failes with the exception below. (Note the assignment to DestinationTable below.)
IDataReader reader = new XmlDataStreamer(/* other stuff here */);
using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy("Server=(local);Database=ScratchDb;Trusted_Connection=True;", SqlBulkCopyOptions.TableLock))
{
sqlBulkCopy.DestinationTableName = "[SchemaPart1.Part2].ImportTable";
sqlBulkCopy.WriteToServer(reader);
}
For the sake of argument, let’s just say that it is beyond our control to change the naming of the schema. After Googling around for a solution, it appeared to be more than a few with the same problem. Now what do we do?
My first thought was to try to figure out if there’s a way to manipulate .Net into accepting the table name. After spending some quality time with Reflector it was time to take a walk and think about something else. I discussed the issue with one of the other developers on the team. While describing the issue a solution took form.
If I can’t change the .Net Framework and I can’t change the schema/table name, maybe I can somehow disguise the table name. Being inspired by dynamic languages lately - If it looks like a table and behaves like a table it must be a table. (Not really, but maybe .Net won’t notice the difference)
Solution: Use a view!
- In the database create a new schema without dots in the name.
- Create a view over the import table with a one-to-one mapping to the table.
That leaves us with a view named: [CompanyNameProjectImport].ImportTableView
The following works:
IDataReader reader = new XmlDataStreamer(/* other stuff here */);
using (SqlBulkCopy sqlBulkCopy = new SqlBulkCopy("Server=(local);Database=ScratchDb;Trusted_Connection=True;", SqlBulkCopyOptions.TableLock))
{
sqlBulkCopy.DestinationTableName = "[CompanyNameProjectImport].ImportTableView";
sqlBulkCopy.WriteToServer(reader);
}