WellKnownText空間データ列を含むSqlBulkCopy DataTable

.net c# sqlbulkcopy sqlgeometry sql-server

質問

私は、次の列を持つ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);

私の元の投稿は、上記を実行すると以下の例外がスローされることを説明できませんでした。

InvalidOperationException:データソースのString型の指定された値を、指定されたターゲット列の型udtに変換できません。

私はこのことから、 SqlBulkCopygeometry列型について知らないと仮定しているため、 stringから変換する方法はわかりません。誰でもこれを確認できますか?

受け入れられた回答

あなたの " SqlGeometry "列は文字列ではなくSqlGeometry型で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<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();                       
    }

私がInsertステートメントを構築するところでは、ストアドプロシージャ呼び出しを行い、必要に応じてパラメータ化することができます。



ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ
ライセンスを受けた: CC-BY-SA with attribution
所属していない Stack Overflow
このKBは合法ですか? はい、理由を学ぶ