带有WellKnownText空间数据列的SqlBulkCopy DataTable

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

  • “ID” – System.Int32
  • “Geom” – 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); 

我的原始post未能解释执行上述操作会导致抛出以下exception。

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

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

您的“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)。

祝好运!

如果desintation表具有与DataTable相同的列结构,则无需映射列。 如果desintation表的结构与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 parameters = new List(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(); } 

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