2012-11-29 139 views
8

我正在嘗試使用由SQL Server管理導入導出嚮導創建的平面文件中的SqlBulkCopy類執行批量插入。這些文件用逗號分隔。在該文件中用SqlBulkCopy插入GUID

一行可以是這樣的:

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

我得到的錯誤是:

System.InvalidOperationException was unhandled
Message=The given value of type String from the data source cannot be converted to type uniqueidentifier of the specified target column.

所以,問題是從字符串轉換爲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, 
+1

顯示一些代碼,請 –

+1

檢查列和它們的類型的數量匹配您的CSV。看起來DB Guid列正在更新來自csv的非guid數據。據我所知,微軟聲明花括號在GUID字符串中是有效的。 – Artemix

+0

@Artemix幾乎肯定是正確的。這將是值得發佈您的目標表DDL。 –

回答

4

的問題是,在{DCAD82A9-32EC-4351-BEDC-2F8291B40AB3},,{ca91e768-072d-4e30-aaf1-bfe32c24008f}空塔被解釋爲''代替NULL 。我只是在我的本地數據庫嘗試過的INSERT STATEMENT,當我指定NULL,而不是'' 的錯誤走了還有另外一個錯誤,你可能會得到:

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

這樣做的原因是,SQL只允許3位小數精度爲毫秒。所以你必須將'2011-04-29 02:54:15.380000000'修整爲'2011-04-29 02:54:15.380',它會正常工作。這樣做會提到here 另外的

的一種方式,你可以修改CsvReader代碼返回的DBNull當值的String.Empty在CsvReader.GetValue(INT)功能。看看here

+0

我喜歡爲其他人添加可能會遇到幾個問題的相同問題。除了上面回答的問題外,Artemix還告訴我列順序很重要。我通過在實際表格中創建具有列名的DataTable並在DataTable上進行映射來解決此問題。 Datatable是SqlBulkCopy類的輸入。通過爲該列設置允許的DbNull,它可以正確加載。 –

0

標準插入到一個唯一標識符列是這樣的(測試和工程),這樣回答格式化問題。列允許空值嗎?

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

+0

是的,並且正如我在帖子中指出的那樣,我嘗試過格式化。那麼也許格式化不是問題。 –

0

我想我找到了那些正在使用流行的免費軟件代碼類稱爲BulkDataReader的答案。我有同樣的問題,我試圖發佈這一點前,但是因爲我問另一個 的問題,並沒有提供一個答案,該帖子被刪除。沒關係,我沒有意識到這違反了規則。

這一次,我有一個答案,所以希望這篇文章會留在這裏。 我要離開我的問題的設置部分,以便它的定義良好,沒有人會爲解決方案不適用於他們而感到困惑。我從 的同事那裏得到了BulkDataReader類的代碼,看起來他可能從另一個知名的答案源獲得了這個,所以每個人都會知道如何從搜索引擎中找到BuldDataReader。

這個問題是建立這樣的:

我也嘗試過各種格式在CSV文件中GUIDS包括: N'3192E434-F479-4B32-B516-AC658F4B7B89' {3192E434-F479 -4B32-B516-AC658F4B7B89} (3192E434-F479-4B32-B516-AC658F4B7B89) 「{3192E434-F479-4B32-B516-AC658F4B7B89}」

從我的CSV一個真正的取樣線將是: 1, AAPL,452.2012,2013-01-24 13:24:27.000,3192E434-F479-4B32-B516-AC658F4B7B89,3192E434-F479-4B32-B516-AC658F4B7B89

如果我刪除2個GUID並導入到沒有這些列的表中,它可以正常工作。 Guid to Unique Identifier列出現此錯誤: Message = {「來自數據源的字符串類型的給定值無法轉換爲指定目標列的類型唯一標識符。」}

我的控制代碼是非常基本的地方,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; 
    } 

我希望這可以幫助別人,對不起我第一次打破了博客規則。

+0

這是一個很棒的發現。我面臨同樣的問題。但請解釋我怎樣才能批量複製使用自定義函數GetValue()?真的很感謝你的幫助... – jaxxbo

2

在您的DataTable.Columns.Add中包含數據類型作爲第二個參數。這應該夠了吧。 例子:

DataTable dt = new DataTable(); 
dt.Columns.Add("ID", typeof(Guid)); 
+0

+1我不知道爲什麼這是downvoted,但這是我的問題。我只用列名創建DataTable,並且除了奇怪的GUID以外,它工作正常。在Exception中嵌套了一個類型轉換異常,所以我認爲這是一個比任何東西都更多的bug,因爲您可以在SQL Server中查詢並插入字符串值的uniqueidentifiers。 – makhdumi

+0

@ Al-Muhandis謝謝。不確定。一個好的做法是放棄投票,甚至是投票,在評論部分給出你的理由。這樣,每個人都可以理解/討論爲什麼某人的解決方案可能存在問題。 –