首页 > 解决方案 > 使用 SqlBulkCopy 和 DbGeography 数据类型插入大量数据

问题描述

我正在使用 SqlBulkCopy 将 10 000 多条记录插入到我的数据库中,但由于 DbGeography 点,它不起作用。

我不断收到一条被抛出的异常消息:

“指定类型未在目标服务器上注册。System.Data.Entity.Spatial.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;
    }

标签: c#sql-server

解决方案


感谢@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 类型,它运行良好。


推荐阅读