我正在使用SqlBulkCopy将10000多条记录插入到我的数据库中,但由于DbGeography点的原因,它无法工作。
我一直收到一条被抛出的异常消息:
"指定的类型未在目标服务器上注册。系统数据实体空间的DbGeography";。
这是我的代码。
public void AddBulkRange(string tableName, List<TEntity> entities)
{
using (var context = new TContext())
{
context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;
string conectionString = context.Database.Connection.ConnectionString;
using (var connection = new SqlConnection(conectionString))
{
connection.Open();
SqlTransaction transaction = connection.BeginTransaction();
using (var bulkCopy = new SqlBulkCopy(connection, SqlBulkCopyOptions.Default, transaction))
{
bulkCopy.BatchSize = 2000;
bulkCopy.DestinationTableName = "dbo." + tableName;
try
{
DataTable data = DataReaderConverterHelper.ToDataTable(entities);
//This just explicitly maps the columns in sqlBulkCopy to the table columns
foreach (DataColumn column in data.Columns)
{
bulkCopy.ColumnMappings.Add(new SqlBulkCopyColumnMapping(column.ColumnName, column.ColumnName));
}
bulkCopy.WriteToServer(data);
}
catch (Exception e)
{
transaction.Rollback();
connection.Close();
}
}
transaction.Commit();
}
}
}
这是ToDataTable方法。
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];
dt.Columns.Add(property.Name, Nullable.GetUnderlyingType(
property.PropertyType) ?? property.PropertyType);
}
object[] values = new object[properties.Count];
foreach (TEntity item in data)
{
for (int i = 0; i < values.Length; i++)
{
values[i] = properties[i].GetValue(item);
}
dt.Rows.Add(values);
}
return dt;
}
问题是DbGeography点正在引发异常。
我的模型中的字段类型。
public System.Data.Entity.Spatial.DbGeography geography_point { get; set; }
在数据库中,字段类型为"地理"。
如果我使用下面的方法,我可以插入,但问题是我得到了一个超时错误,这就是为什么我想使用SqlBulkCopy,但正如我上面所说的,它不起作用,因为只有一种数据类型。
public List<TEntity> AddRange(List<TEntity> entities)
{
int takeCount = 100;
int counter = (entities.Count % takeCount) == 0
? (entities.Count / takeCount)
: (entities.Count / takeCount) + 1;
for (int i = 0; i < counter; i++)
{
using (var context = new TContext())
{
List<TEntity> subList = entities.Skip(i * takeCount).Take(takeCount).ToList();
context.Configuration.AutoDetectChangesEnabled = false;
context.Configuration.ValidateOnSaveEnabled = false;
context.Set<TEntity>().AddRange(subList);
context.SaveChanges();
context.Dispose();
}
}
return entities;
}
多亏了@AlwaysLearning的一些输入,我做了一些更改,并使DbGeography与数据表一起工作。
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];
if (property.PropertyType.Name == "DbGeography")
{
dt.Columns.Add(property.Name, typeof(SqlGeography));
continue;
}
dt.Columns.Add(property.Name, Nullable.GetUnderlyingType(
property.PropertyType) ?? property.PropertyType);
}
object[] values = new object[properties.Count];
foreach (TEntity item in data)
{
for (int i = 0; i < 20; i++)
{
if (properties[i].PropertyType.Name == "DbGeography")
{
DbGeography Point = (DbGeography)properties[i].GetValue(item);
SqlGeography newGeography = SqlGeography.Parse(Point.AsText()).MakeValid();
values[i] = newGeography;
continue;
}
values[i] = properties[i].GetValue(item);
}
dt.Rows.Add(values);
}
return dt;
}
我所做的只是将DbGeography数据类型转换为SqlGeography类型,它运行得很好。