"指定的类型未注册"批量插入具有地理空间数据类型的表时出错

时间:2016-07-16 04:21:36

标签: c# sql-server entity-framework

我尝试使用SqlBulkCopy程序集(4.6.1)中的System.Data类来批量插入具有地理空间数据类型的表,使用看起来大致相似的代码(改编自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

我用Google搜索,但没有多大用处。我已经跟踪了调用链,深入到了SqlBulkCopy程序集的内容中(感谢,Resharper!),但错误似乎隐藏得比我能够挖掘的更深。我已经尝试安装(并加载)相应的SQL Server Types包(https://www.nuget.org/packages/Microsoft.SqlServer.Types/),但没有骰子。

有什么建议吗?

2 个答案:

答案 0 :(得分:2)

好的,我想我已经修好了。有问题的代码在GetValue(int ordinal)类中(我从https://github.com/MikaelEliasson/EntityFramework.Utilities/blob/master/EntityFramework.Utilities/EntityFramework.Utilities/EFDataReader.cs借来的)。它的public override object GetValue(int ordinal) { return Accessors[ordinal](Enumerator.Current); } 最初看起来像这样:

DbGeometry

但这意味着它返回的任何与数据库无关的DbGeographyDbGeometry值恰好通过作为 DbGeographySqlGeography ,这是SqlBulkCopy类不明白的。它们实际上需要特定于SQL Server,即SqlGeometrypublic 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; } ,如下所示:

==

答案 1 :(得分:0)

  

FORWARD:我意识到我的专业知识不在C# 尚未,所以我只能从我自己的ETL类似的经验中得出你的错误。   可能,问题可能归结为你对这个问题的假设   格式良好的数据以及如何将其输入SQL

来自MSDN的Spatial Data Types之旅告诉我们数据需要格式良好....我们已经知道了......但我们是否已经假设了源数据?

您正在使用来自外部来源的CSVLoader,根据我自己使用SSIS的经验,数据并非始终在文件中正确构建。如上所述,SQL Server会对违反列数据类型约束的格式错误的spatial data types感到不满。

  • 在使用通话方法之前,您是否已对数据进行了限定?
  • 您使用的是spatial datatypes的{​​{1}}吗?
  • 您是否尝试过分割批量数据以测试instantiable检索它们的整个文件的一致性?也许只有部分数据是腐败的。

由于这是一个集成操作,您是否考虑过设置一个临时表来处理假定格式良好的数据的清理/转换?

CSVLoader文件是简单的文本文件,因此CSVCSVLoader尝试将批量插入数据库时​​之间存在隐式/显式转换。 SQL Server不能违反SQL Server元素。

我不能强调不要假设您的数据中的事实以及ACID,更不用说C#如何读取和转换它们。我花了很多一个小时在SQL Server中使用简单的CSV文件,然后才意识到我的SSIS正在以无法处理IS中的不一致的方式解析文件文件(某些数据已损坏或丢失)。

希望这可以帮助您解决问题。

干杯,