8

SqlBulkCopySQL Server Management Import Export Wizard によって作成されたフラットファイルからクラスを一括挿入しようとしています。ファイルはコンマで区切られています。

ファイルの 1 行は次のようになります。

{DCAD82A9-32EC-4351-BEDC-2F8291B40AB3},,{ca91e768-072d-4e30-aaf1-bfe32c24008f},900001:1792756,900001:1792757,basladdning,2011-04-29 02:54:15.18 02:54:15.18 04-29 02:54:15.380000000、{20A3C50E-8029-41DE-86F1-DDCDB9A78BA5}

私が得るエラーは次のとおりです。

System.InvalidOperationException は処理
されませんでした。メッセージ = データ ソースからの String 型の指定された値を、指定されたターゲット列の uniqueidentifier 型に変換できません。

したがって、問題は文字列から GUID への変換です。

私は次のことを試しました:

  • UTF8とANSIの異なるエンコーディングを試しました
  • GUIDS を囲む { } を削除しました
  • { } の有無にかかわらず、GUIDS の前後に ' ' を追加

助言がありますか?'' があるフラット ファイルには、データ型として Guid を持つ列もあります。列は、ウィザードが '' としてエクスポートした場所で NULL です。それが問題でしょうか?

コード:

using (var file = new StreamReader(filePath))
using (var csv = new CsvReader(file, false)) 
using (var bcp = new SqlBulkCopy(CreateConnectionString()))
{
    bcp.DestinationTableName = "table";
    bcp.WriteToServer(csv);
}

テーブル定義:

CREATE TABLE [beata].[T_FeatureInstance]( 
    [FeatureInstanceId] [uniqueidentifier] NOT NULL, 
    [FeatureInstanceParentId] [uniqueidentifier] NULL, 
    [FeatureTypeAliasId] [uniqueidentifier] NOT NULL, 
    [Uuid] [varchar](1000) NOT NULL, 
    [VersionId] [varchar](50) NOT NULL, 
    [SkapadAv] [varchar](255) NULL, 
    [Skapad] [datetime] NOT NULL, 
    [UppdateradAv] [varchar](255) NOT NULL, 
    [Uppdaterad] [datetime] NOT NULL, 
    [Gs] [uniqueidentifier] NOT NULL,
4

4 に答える 4

5

DataTable.Columns.Add2 番目のパラメーターとしてデータ型を含めます。これでうまくいくはずです。例:

DataTable dt = new DataTable();
dt.Columns.Add("ID", typeof(Guid));
于 2016-11-25T17:10:29.080 に答える
4

問題は、 の空の列がではなく{DCAD82A9-32EC-4351-BEDC-2F8291B40AB3},,{ca91e768-072d-4e30-aaf1-bfe32c24008f}として解釈されていることです。ローカル データベースで を試したところ、 There is another error you could get:''NULLINSERT STATEMENTNULL''

Conversion failed when converting date and/or time from character string.

これは、SQL ではミリ秒単位で 3 桁の 10 進精度しか許可されていないためです。したがって、 に丸める必要があり'2011-04-29 02:54:15.380000000''2011-04-29 02:54:15.380'うまく機能します。

これを行う 1 つの方法は、ここで説明したとおりです 。別の方法として、CsvReader.GetValue(int) 関数で値が string.Empty の場合に DBNULL を返すように CsvReader コードを変更することもできます。こちらをご覧ください

于 2012-11-29T16:03:10.283 に答える
4

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;
    }

これが誰かの役に立てば幸いです。申し訳ありませんが、初めてブログのルールを破りました。

于 2013-02-07T01:18:24.880 に答える
0

uniqueidentifier 列への標準的な挿入は次のようになります (テスト済みで機能します)。これで、フォーマットに関する質問に答えます。列はヌルを許可しますか?

INSERT INTO dbo.TableName([GUID]) VALUES('20A3C50E-8029-41DE-86F1-DDCDB9A78BA5')

于 2012-11-29T14:10:20.093 に答える