2016-07-16 53 views
3

我試圖使用System.Data程序集(4.6.1)中的SqlBulkCopy類使用代碼批量插入具有地理空間數據類型的表看起來大致是這樣(改編自https://github.com/MikaelEliasson/EntityFramework.Utilities):使用地理空間數據類型批量插入表時出現「指定類型未註冊」錯誤

public void InsertItems<T>(IEnumerable<T> items, string schema, string tableName, IList<ColumnMapping> properties, DbConnection storeConnection, int? batchSize) 
{ 
    using (var reader = new EFDataReader<T>(items, properties)) 
    { 
     var con = (SqlConnection)storeConnection; 
     if (con.State != ConnectionState.Open) 
     { 
      con.Open(); 
     } 
     using (var copy = new SqlBulkCopy(con)) 
     { 
      copy.BatchSize = batchSize ?? 15000; //default batch size 
      if (!string.IsNullOrWhiteSpace(schema)) 
      { 
       copy.DestinationTableName = $"[{schema}].[{tableName}]"; 
      } 
      else 
      { 
       copy.DestinationTableName = "[" + tableName + "]"; 
      } 

      copy.NotifyAfter = 0; 

      foreach (var i in Enumerable.Range(0, reader.FieldCount)) 
      { 
       copy.ColumnMappings.Add(i, properties[i].NameInDatabase); 
      } 
      copy.WriteToServer(reader); // <-- throws here 
      copy.Close(); 
     } 
    } 
} 

直到我嘗試使用它與地理空間數據的表的偉大工程。當我這樣做時,我得到以下錯誤:

ERROR Swyfft.Console.TaskManager - Error running task SeedRating: 
(InvalidOperationException) The given value of type DbGeography from the data source cannot be converted to type udt of the specified target column.; 
(ArgumentException) Specified type is not registered on the target server.System.Data.Entity.Spatial.DbGeography, EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089.; 
    at Swyfft.Data.Utilities.SqlQueryProvider.InsertItems[T](IEnumerable`1 items, String schema, String tableName, IList`1 properties, DbConnection storeConnection, Nullable`1 batchSize) in C:\source\swyfft\swyf-website\Swyfft.Data.Utilities\SqlQueryProvider.cs:line 78 
    at Swyfft.Data.Utilities.EFBatchOperation`2.InsertAll[TEntity](IEnumerable`1 items, DbConnection connection, Nullable`1 batchSize) in C:\source\swyfft\swyf-website\Swyfft.Data.Utilities\EFBatchOperation.cs:line 138 
    at Swyfft.Data.Rating.RatingContext.BulkInsert[T](IEnumerable`1 entities, Nullable`1 batchSize) in C:\source\swyfft\swyf-website\Swyfft.Data.Rating\RatingContext.cs:line 69 
    at Swyfft.Seeding.CsvLoaders.CsvLoader.ProcessCsv[T](StreamReader streamReader, String fileName, ISwyfftContext ctx, Func`2 parserFunc) in C:\source\swyfft\swyf-website\Swyfft.Seeding\CsvLoaders\CsvLoader.cs:line 133 
    at Swyfft.Seeding.CsvLoaders.CsvLoader.InitializeCountyBlockQualities(String stateFilter) in C:\source\swyfft\swyf-website\Swyfft.Seeding\CsvLoaders\InitializeCountyBlockQualities.cs:line 35 

我已經搜索了一下,沒有太大的效果。我追蹤了調用鏈,深入到SqlBulkCopy程序集的內部(謝謝,Resharper!),但是這個錯誤似乎隱藏得比我能挖掘的更深。我試過安裝(和加載)適當的SQL Server Types包(https://www.nuget.org/packages/Microsoft.SqlServer.Types/),但沒有骰子。

有什麼建議嗎?

+0

是個壞主意。我解決了我自己的問題。 –

回答

1

好吧,我想我已經修好了。有問題的代碼在EFDataReader<T>班(我從https://github.com/MikaelEliasson/EntityFramework.Utilities/blob/master/EntityFramework.Utilities/EntityFramework.Utilities/EFDataReader.cs借來的)。它最初GetValue(int ordinal)是這樣的:

public override object GetValue(int ordinal) 
{ 
    return Accessors[ordinal](Enumerator.Current); 
} 

但是,這意味着它是返回任何DB無關DbGeometryDbGeography值所發生過來作爲DbGeometryDbGeography,其中SqlBulkCopy類不明白。他們實際上需要SQL-Server特定的,即SqlGeographySqlGeometry,像這樣:用我的電話

public override object GetValue(int ordinal) 
{ 
    object value = Accessors[ordinal](Enumerator.Current); 

    var dbgeo = value as DbGeography; 
    if (dbgeo != null) 
    { 
     var chars = new SqlChars(dbgeo.WellKnownValue.WellKnownText); 
     return SqlGeography.STGeomFromText(chars, dbgeo.CoordinateSystemId); 
    } 

    var dbgeom = value as DbGeometry; 
    if (dbgeom != null) 
    { 
     var chars = new SqlChars(dbgeom.WellKnownValue.WellKnownText); 
     return SqlGeometry.STGeomFromText(chars, dbgeom.CoordinateSystemId); 
    } 

    return value; 
} 
0

FORWARD: I realize my expertise is not in C#yet, so I can only draw from my own ETL experiences that is similar to your error. Likely, the problem may come down to your assumptions about the well-formed nature of the data and how this is being fed into SQL .

從MSDN到Spatial Data Types之旅告訴我們,需要對數據進行格式良好的....我們已經知道了......但我們認爲這樣對源數據?

您正在使用CSVLoader,其中來自外部來源,並且在使用SSIS我自己的經驗,數據並不總是在文件結構正確。如前所述,SQL Server將會違反不合格的spatial data types,這違反了列數據類型約束。

  • 您在使用呼叫方法之前是否限定了您的數據?
  • 您使用spatial datatypesinstantiable
  • 您是否嘗試過分解批量數據以測試整個文件中的一致性CSVLoader檢索它們?也許只有部分數據損壞。

由於這是一個集成操作,您是否考慮設置一個臨時表來處理假定格式良好的數據的清理/轉換?

CSV文件是簡單的文本文件,因此在CSVLoaderSQL Server嘗試按行批量插入數據庫之間存在隱式/顯式轉換。 SQL Server不能違反ACID元素。

我不能強調不要從您的數據中假設事實,並且C#,更不用說SQL Server,讀取和轉換它們。我花了很多小時在SSIS中與簡單的CSV文件掙扎,然後才意識到我的IS解析文件的方式無法處理CSV文件中的不一致(某些數據已損壞或丟失)。

希望這可以幫助你解決問題。

乾杯,

+0

感謝您的意見。在這種情況下,我碰巧知道文件形成正確 - 以前使用EntityFramework.BulkInsert庫正確加載文件 - 請參閱https://efbulkinsert.codeplex.com/。不幸的是,該庫有一個不允許它解析多列外鍵的錯誤,當我們添加一個外鍵時它就停止工作。所以我試圖尋找替代方案。 –

+0

@ Ken.Smith也許可以使用ETL策略?您的目標是以一種不會丟失信息的方式將其加入到SQL Server中,對嗎?你能否安全地將任何數據類型轉換爲空間數據類型?您可以隨時解決問題,而不必失去今天的數據。 –

相關問題