【问题标题】:SqlBulkCopy DataTable with WellKnownText spatial data column具有 WellKnownText 空间数据列的 SqlBulkCopy DataTable
【发布时间】:2011-04-26 15:15:07
【问题描述】:

我正在尝试批量复制具有以下列的DataTable

  • “ID”-System.Int32
  • “几何”-System.String

进入具有以下列的 SQL 数据库:

  • “ID”-int
  • “形状”-geometry

任何人都可以建议最好的方法吗?

一些测试代码,如果有帮助的话......

DataTable dataTable = new DataTable();
dataTable.Columns.Add("ID", typeof(Int32));
dataTable.Columns.Add("Geom", typeof(String));

dataTable.Rows.Add(1, "POINT('20,20')");
dataTable.Rows.Add(1, "POINT('40,25')");
dataTable.Rows.Add(1, "POINT('60,30')");

SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(connection);
sqlBulkCopy.DestinationTableName = "MySpatialDataTable";
sqlBulkCopy.WriteToServer(dataTable);

我的原始帖子未能解释执行上述操作会导致引发以下异常。

InvalidOperationException:来自数据源的String类型的给定值无法转换为指定目标列的udt类型。

据此我假设SqlBulkCopy 不知道geometry 列类型,因此不知道如何从string 转换为它。谁能证实这一点?

【问题讨论】:

    标签: c# .net sql-server sqlbulkcopy sqlgeometry


    【解决方案1】:

    您的“Geom”列需要输入SqlGeometry,而不是字符串。 Sql Server 将期望插入时几何列的用户定义类型 (UDT)。这就是我要使用的:

    DataTable dataTable = new DataTable();
    dataTable.Columns.Add("ID", typeof(Int32));
    dataTable.Columns.Add("Geom", typeof(SqlGeometry));
    
    dataTable.Rows.Add(1, SqlGeometry.STGeomFromText("POINT('20,20')"));
    dataTable.Rows.Add(2, SqlGeometry.STGeomFromText("POINT('40,25')"));
    dataTable.Rows.Add(3, SqlGeometry.STGeomFromText("POINT('60,30')"));
    
    SqlBulkCopy sqlBulkCopy = new SqlBulkCopy(connection);
    sqlBulkCopy.DestinationTableName = "MySpatialDataTable";
    sqlBulkCopy.WriteToServer(dataTable);
    

    请注意,我们从您的字符串构造实际的 SqlGeometry 类型。批量插入将负责将其转换为 SqlServer 可以识别的二进制格式。

    另外,我不确定您为什么要插入具有相同 ID 的多条记录(您的示例中的所有 ID 都为 1)。

    祝你好运!

    【讨论】:

    【解决方案2】:

    如果目标表与您的 DataTable 具有相同的列结构,则不需要映射列。如果目标表的结构与您的 DataTable 不同,则您必须映射每一列。

    public void BulkLoadToTemp(DataTable dt, String tableName, int bulkLoadBatchSize)
        {
            using (SqlBulkCopy bulkCopy = new SqlBulkCopy(this._connection))
            {
                bulkCopy.DestinationTableName = tableName;
                bulkCopy.BulkCopyTimeout = 120;
                bulkCopy.BatchSize = bulkLoadBatchSize;
                bulkCopy.WriteToServer(dt);
                bulkCopy.Close();
            }            
        }
    

    刚刚意识到,您没有在 sql 列中使用 varchar。在这种情况下,我认为最好的办法是使用 sp 填充表,并使用数组绑定执行存储过程。这是我使用 Oracle 做的一个例子。使用sql server的时候可以修改和简化很多。

    public void BulkLoadWithArrayBinding(System.Data.DataTable dt)
        {
            StringBuilder sb = new StringBuilder();
            List<OracleParameter> parameters = new List<OracleParameter>(dt.Columns.Count);
    
            OracleCommand cmd = new OracleCommand();
            cmd.Connection = conn;
    
            sb.Append("INSERT INTO \"" + dt.TableName + "\" (");
            foreach (DataColumn dc in dt.Columns)
            {
                sb.Append("\"" + dc.ColumnName.ToUpper() + "\"");
                if (dc.Ordinal < dt.Columns.Count - 1)
                    sb.AppendLine(",");
            }
            sb.Append(") VALUES(");
            foreach (DataColumn dc in dt.Columns)
            {
                string parameterName = dc.ColumnName.ToUpper();
    
                sb.Append(":" + parameterName);
                if (dc.Ordinal < dt.Columns.Count - 1)
                    sb.AppendLine(",");
    
                OracleString[] sArray = null;
                OracleDate[] dArray = null;
                OracleDecimal[] dbArray = null;
    
                OracleParameter p = null;
                if (dc.DataType.Name == "String")
                {
                    sArray = new OracleString[dt.Rows.Count];
                    for (int i = 0; i < dt.Rows.Count; i++)
                    {
                        if (dt.Rows[i][dc.Ordinal] != DBNull.Value)
                            sArray[i] = dt.Rows[i][dc.Ordinal].ToString();
                        else
                            sArray[i] = OracleString.Null;
                    }
    
                    p = new OracleParameter(parameterName,OracleDbType.Varchar2, dt.Rows.Count, ParameterDirection.Input);
                    p.Size = sArray.Length;
                    p.Value = sArray;
                }
                else if (dc.DataType.Name == "DateTime")
                {
                    dArray = new OracleDate[dt.Rows.Count];
                    for (int i = 0; i < dt.Rows.Count; i++)
                    {
                        if (dt.Rows[i][dc.Ordinal] != DBNull.Value)
                            try
                            {
                                dArray[i] = (OracleDate)Convert.ToDateTime(dt.Rows[i][dc.Ordinal]);
                            }
                            catch
                            {
                                object o = dt.Rows[i][dc.Ordinal];
                                dArray[i] = OracleDate.Null;
                            }
                        else
                        {
                            dArray[i] = OracleDate.Null;
                        }
                    }
    
                    p = new OracleParameter(parameterName,OracleDbType.Date, dt.Rows.Count, ParameterDirection.Input);
                    p.Size = dArray.Length;
                    p.Value = dArray;
                }
                else if (dc.DataType.Name == "Double")
                {
                    dbArray = new OracleDecimal[dt.Rows.Count]; ;
                    for (int i = 0; i < dt.Rows.Count; i++)
                    {
                        if (dt.Rows[i][dc.Ordinal] != DBNull.Value)
                            dbArray[i] = Convert.ToDecimal(dt.Rows[i][dc.Ordinal]);
                        else
                            dbArray[i] = OracleDecimal.Null;
                    }
    
                    p = new OracleParameter(parameterName, OracleDbType.Decimal, dt.Rows.Count, ParameterDirection.Input);
                    p.Value = dbArray;
                }
                else if (dc.DataType.Name == "Boolean")
                {
                    dbArray = new OracleDecimal[dt.Rows.Count]; ;
                    for (int i = 0; i < dt.Rows.Count; i++)
                    {
                        if (dt.Rows[i][dc.Ordinal] != DBNull.Value)
                            dbArray[i] = Convert.ToDecimal(dt.Rows[i][dc.Ordinal]);
                        else
                            dbArray[i] = OracleDecimal.Null;
                    }
    
                    p = new OracleParameter(parameterName, OracleDbType.Decimal, dt.Rows.Count, ParameterDirection.Input);
                    p.Value = dbArray;
                }
    
                cmd.Parameters.Add(p);
            }
    
            sb.AppendLine(")");
    
            cmd.CommandText = sb.ToString();
            cmd.CommandType = CommandType.Text;
            cmd.ArrayBindCount = dt.Rows.Count;
            cmd.BindByName = true;
            cmd.AddToStatementCache = true;
    
            cmd.ExecuteNonQuery();
    
            foreach (OracleParameter p in cmd.Parameters)
            {                
                p.Dispose();
            }
    
            cmd.Dispose();                       
        }
    

    在我构建插入语句的地方,您可以进行存储过程调用,并根据需要进行参数化。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-21
      • 2017-01-02
      • 1970-01-01
      • 2012-05-28
      相关资源
      最近更新 更多