I think I found the answer for those using the popular free code class called BulkDataReader. I have the same problem, and I tried to post this a little back, but since I asked another question and did not give an answer that the message was deleted. This is normal, I did not understand that this is against the rules.
This time I have an answer, so hopefully this post will stay here. I am going to leave part of the setup of my problem so that it is clearly defined, and no one is confused by why the solution does not work for them. I got the code for the BulkDataReader class from a colleague, and it looks like he could get it from another well-known answer source so that everyone knows how to find BuldDataReader from a search engine.
This issue is configured as follows:
I also tried all kinds of formats for GUIDS in a CSV file, including: N3192E434-F479-4B32-B516-AC658F4B7B89 {3192E434-F479-4B32-B516-AC658F4B7B89} (3192E434-F479-4B32-B516-AC9484F4B4B4F4F4B4B4F4F4F4B4F4F4F4F4B4F4F4F4F4F4F4F4F4F4F4F4FBF 4B32-B516-AC658F4B7B89} "
The real sampling string from my CSV will be: 1, AAPL, 452.2012,2013-01-24 13: 24: 27.000,3192E434-F479-4B32-B516-AC658F4B7B89,3192E434-F479-4B32-B516-AC658F4B7B89
If I delete 2 Guides and import them into a table without these columns, it works fine. With Guides to Unique Identifier columns, I get this error: Message = {"This String value from the data source cannot be converted to enter a unique identifier for the specified target column." }
My control code is pretty simple, where the BulkDataReader is rather cumbersome to walk around, so be prepared if you are trying to debug it.
using (IDataReader reader = new BulkDataReader(new StreamReader("C:\\test.csv"), false)) { String connectionStr = GetConnString(); SqlConnection connection = new SqlConnection(connectionStr); connection.Open(); SqlTransaction transaction = connection.BeginTransaction(); try { SqlBulkCopy copy = new SqlBulkCopy(connection, SqlBulkCopyOptions.TableLock, transaction); copy.DestinationTableName = "TestTable6"; copy.WriteToServer(reader); //ERROR OCCURS HERE: The given value of type String from the data source cannot be converted to type uniqueidentifier of the specified target column transaction.Commit(); } catch (Exception exe) { transaction.Rollback(); } finally { connection.Close(); } }
Thus, the error does indeed occur in the .NET SqlBulkCopy class. However, this happens immediately after BulkDataReader reads the Guid value. This GetValue method is called from an external code. It means that it was buried in plumbing between StreamReader BulkDataReader and StreamWriting material in the SqlBulkCopy class. There was no need to delve into all my favorite reflection utility. I found that when the BulkDataReader IDataRecord.GetValue (int i) method returns a string that really is a Guid, SqlBulkCopy cannot convert this string to a unique identifier, no matter what format it is in. Probably some kind of obscure and coding format, but I could not find one that would work. However, if I simply return the value as the correct type of System.Guid, then SqlBulkCopy simply converts it to a unique identifier. So a simple solution to what seems like a nightmare serialization issue. Just copy the entire IDataRecord.GetValue (int i) method with this and should work. I tried many CLR data types for SQL, but not all of them, so there may be another where you should play this deserialization game, but this should solve the problem for the most part.
object IDataRecord.GetValue(int i) { ValidateDataReader(DataReaderValidations.IsInitialized | DataReaderValidations.IsNotClosed); if (((IDataRecord)this).IsDBNull(i)) return DBNull.Value; else { //For some reason the SqlBulkCopy.WriteToServer method will call this GetValue method when reading //the value and it doesn't seem to know how to convert the string value of a Guid to a unique identifier. //However, it does actually know how to convert a System.Guid to a UniqueIdentifer so we can return that if //the value parses to Guid if (IsGuid(this[i])) return Guid.Parse(this[i]); else return this[i]; } } bool IsGuid(object value) { if (value != null) { Guid testGuid = Guid.Empty; if (Guid.TryParse(value.ToString(), out testGuid)) return true; } return false; }
I hope this helps someone and itβs a pity that I first violated the rules of the blog.