Sqlserver
 sql >> Base de Dados >  >> RDS >> Sqlserver

A tabela de dados contendo SqlGeometry está causando falha na execução do procedimento armazenado... Por quê?


Desde que fiz um breve comentário sobre sua pergunta, tive a chance de brincar completamente com as opções. Parece que no momento (mesmo tentando .NET 4.6 e SQL 2014) você não pode definir SqlGeography OU SqlGeometry como o typeof() parâmetro ao definir uma coluna para um DataTable . Para maior clareza, você pode fazer isso em .NET e até preenchê-lo, mas não pode passar essa tabela como um TVP para um procedimento armazenado.

Existem duas opções.

Opção 1. Passe o valor no formato WKT.

Defina seu tipo de tabela da seguinte maneira.
CREATE TYPE [dbo].[WKT_Example] AS TABLE
(
    [geom] [varchar](max) NOT NULL
)

Em seguida, defina seu procedimento armazenado da seguinte maneira.
CREATE PROCEDURE [dbo].[BulkInsertFromWKT]

    @rows [dbo].[WKT_Example] READONLY

AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    INSERT INTO [dbo].[Table1]
        ([SpatialData])
    SELECT
        geometry::STGeomFromText(R.[SpatialData], 4326)
    FROM
        @rows R;

END

Defina seu .NET DataTable da seguinte forma:
DataTable wktTable = new DataTable();
wktTable.Columns.Add("SpatialData", typeof(string));

Preencha-o da seguinte forma:
for (int j = 0; j < geometryCollection.Count; j++)
{
    System.Data.SqlTypes.SqlString wkt = geometryCollection[j].STAsText().ToSqlString();

    wktTable.Rows.Add(wkt.ToString());
}

Opção 2. Passe o valor no formato WKB.

Defina seu tipo de tabela da seguinte maneira.
CREATE TYPE [dbo].[WKB_Example] AS TABLE
(
    [geom] [varbinary](max) NOT NULL
)

Em seguida, defina seu procedimento armazenado da seguinte maneira.
CREATE PROCEDURE [dbo].[BulkInsertFromWKB]

    @rows [dbo].[WKB_Example] READONLY

AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    INSERT INTO [dbo].[Table1]
        ([SpatialData])
    SELECT
        geometry::STGeomFromWKB(R.[SpatialData], 4326)
    FROM
        @rows R;

END

Defina seu .NET DataTable da seguinte forma:
DataTable wkbTable = new DataTable();
wkbTable.Columns.Add("SpatialData", typeof(System.Data.SqlTypes.SqlBytes));

Preencha-o da seguinte forma:
for (int j = 0; j < geometryCollection.Count; j++)
{
    wkbTable.Rows.Add(geographyCollection[j].STAsBinary());
}

Observações:

Defina seu SqlParameter da seguinte forma:
SqlParameter p = new SqlParameter("@rows", SqlDbType.Structured);
p.TypeName = "WKB_Example"; // The name of your table type
p.Value = wkbTable;

Deixei um SRID de 4326 no meu trabalho de geografia. Você pode alterar isso para o que quiser - e, de fato, se estiver usando Geography Eu sugeriria torná-lo um segundo parâmetro para lhe dar flexibilidade.

Além disso, se o desempenho for crítico, você achará melhor usar o WKB. Meus testes descobriram que o WKB foi concluído em 45% a 65% do tempo que o WKT levou. Isso varia de acordo com a complexidade de seus dados e sua configuração.

As informações que você encontrou ao especificar o UdtTypeName do parâmetro como "Geometria" / "Geography" está correto quando seu Stored Procedure tem um parâmetro do tipo [Geometry] ou [Geography]. Não se aplica a TVPs.