BulkDataReader と呼ばれる一般的なフリーウェア コード クラスを使用している方への回答を見つけたと思います。私は同じ問題を抱えており、少し前にこれを投稿しようとしましたが、別の質問をして回答を提供しなかったため、投稿が削除されました. 大丈夫です、それがルール違反だとは知りませんでした。
今回は答えが出たので、この投稿はここにとどまることを願っています。問題のセットアップ部分は残しておきます。問題が明確に定義されており、解決策が機能しない理由について誰も混乱することはありません。私は同僚から BulkDataReader クラスのコードを入手しましたが、検索エンジンから BuldDataReader を見つける方法を誰もが知っているように、彼は別のよく知られた回答ソースからコードを入手したようです。
この問題は次のように設定されています。
私も、次のような CSV ファイルの GUIDS のあらゆる種類の形式を試しました: N'3192E434-F479-4B32-B516-AC658F4B7B89' )「{3192E434-F479-4B32-B516-AC658F4B7B89}」</p>
私の CSV からの実際のサンプル行は次のようになります。
2 つの Guid を削除して、それらの列のないテーブルにインポートすると、正常に動作します。Guids to Unique Identifier 列を使用すると、次のエラーが表示されます。
私の制御コードは非常に基本的なもので、BulkDataReader を実行するのは非常に面倒なので、デバッグしようとしている場合は準備しておいてください。
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();
}
}
したがって、エラーは実際には .NET SqlBulkCopy クラス内で発生しています。ただし、BulkDataReader が Guid 値を読み取った直後に発生します。その GetValue メソッドは外部コードから呼び出されます。つまり、BulkDataReader の streamReader と SqlBulkCopy クラスの StreamWriting の間の配管に埋もれています。私のお気に入りのリフレクション ユーティリティを使用して、すべてを掘り下げる必要はありませんでした。BulkDataReader のメソッド IDataRecord.GetValue(int i) が実際には Guid である文字列を返す場合、SqlBulkCopy はその文字列がどのような形式であっても、その文字列を一意の識別子に変換できないことがわかりました。あいまいなエンコード形式がいくつかある可能性がありますが、できましたうまくいくものを見つけられません。ただし、値を適切な System.Guid 型として単純に返すと、SqlBulkCopy はそれを一意の識別子に変換します。したがって、悪夢のようなシリアライゼーションの問題と思われるものに対する簡単な解決策です。これで IDataRecord.GetValue(int i) メソッド全体をコピーするだけで動作するはずです。CLR から SQL へのデータ型の多くを試しましたが、すべてではありませんでした。そのため、この逆シリアル化ゲームをプレイしなければならない別の型が存在する可能性がありますが、これでほとんどの問題は解決するはずです。
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;
}
これが誰かの役に立てば幸いです。申し訳ありませんが、初めてブログのルールを破りました。