使用SqlBulkCopy插入含DbGeography类型数据提示类型未注册问题问询
解决方案
核心原因
报错本质是SqlBulkCopy原生不识别Entity Framework封装的System.Data.Entity.Spatial.DbGeography类型,只有SqlServer官方的Microsoft.SqlServer.Types.SqlGeography类型才能被SqlBulkCopy识别并映射到数据库的Geography字段。
具体修复步骤
- 第一步:安装NuGet包
给你的项目安装Microsoft.SqlServer.TypesNuGet包,版本需和你使用的SqlServer版本兼容。 - 第二步:修改
ToDataTable扩展方法
对空间类型的字段做特殊处理,将DbGeography转成SqlGeography后再存入DataTable,修改后的代码如下:
using Microsoft.SqlServer.Types; using System.Data.Entity.Spatial; public static DataTable ToDataTable<TEntity>(this IList<TEntity> data) { PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(TEntity)); DataTable dt = new DataTable(); for (int i = 0; i < properties.Count; i++) { PropertyDescriptor property = properties[i]; Type columnType; // 单独处理DbGeography类型 if (property.PropertyType == typeof(DbGeography)) { columnType = typeof(SqlGeography); } else { columnType = Nullable.GetUnderlyingType(property.PropertyType) ?? property.PropertyType; } dt.Columns.Add(property.Name, columnType); } object[] values = new object[properties.Count]; foreach (TEntity item in data) { for (int i = 0; i < values.Length; i++) { var value = properties[i].GetValue(item); // 单独转换DbGeography到SqlGeography if (value is DbGeography geoValue) { // 直接取ProviderValue即可,EF封装的DbGeography底层就是SqlGeography values[i] = geoValue.ProviderValue ?? DBNull.Value; } else { values[i] = value ?? DBNull.Value; } } dt.Rows.Add(values); } return dt; }
- 第三步:添加类型重定向(可选,遇到版本报错时添加)
如果运行时提示Microsoft.SqlServer.Types版本不匹配,在项目的配置文件(App.config/Web.config)的<runtime>节点下添加如下配置:
<dependentAssembly> <assemblyIdentity name="Microsoft.SqlServer.Types" publicKeyToken="89845dcd8080cc91" culture="neutral" /> <bindingRedirect oldVersion="0.0.0.0-16.0.0.0" newVersion="16.0.0.0" /> </dependentAssembly>
注意把newVersion改成你实际安装的Microsoft.SqlServer.Types包的版本号。
优化提示
你原来的AddBulkRange方法里catch异常后已经回滚了事务,不需要手动调用connection.Close(),using语句会自动释放连接资源,可以删掉这行冗余代码。
内容的提问来源于stack exchange,提问作者ID10T_E330r
相关产品推荐
相关产品推荐

