Sqlserver
 sql >> Database >  >> RDS >> Sqlserver

Il datatable contenente SqlGeometry sta causando il fallimento dell'esecuzione della procedura memorizzata... Perché?

Da quando ho fatto un breve commento sulla tua domanda, ho avuto la possibilità di giocare completamente con le opzioni. Sembra che al momento (anche provando .NET 4.6 e SQL 2014) non sia possibile impostare SqlGeography OPPURE SqlGeometry come typeof() parametro quando si definisce una colonna per una DataTable . Per assoluta chiarezza, puoi farlo in .NET e persino popolarlo, ma non puoi quindi passare quella tabella come TVP a una stored procedure.

Ci sono due opzioni.

Opzione 1. Passa il valore in formato WKT.

Definisci il tipo di tabella come segue.

CREATE TYPE [dbo].[WKT_Example] AS TABLE
(
    [geom] [varchar](max) NOT NULL
)

Quindi definisci la tua stored procedure come segue.

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

Definisci il tuo DataTable .NET come segue:

DataTable wktTable = new DataTable();
wktTable.Columns.Add("SpatialData", typeof(string));

Compilalo come segue:

for (int j = 0; j < geometryCollection.Count; j++)
{
    System.Data.SqlTypes.SqlString wkt = geometryCollection[j].STAsText().ToSqlString();

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

Opzione 2. Passa il valore in formato WKB.

Definisci il tipo di tabella come segue.

CREATE TYPE [dbo].[WKB_Example] AS TABLE
(
    [geom] [varbinary](max) NOT NULL
)

Quindi definisci la tua stored procedure come segue.

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

Definisci il tuo DataTable .NET come segue:

DataTable wkbTable = new DataTable();
wkbTable.Columns.Add("SpatialData", typeof(System.Data.SqlTypes.SqlBytes));

Compilalo come segue:

for (int j = 0; j < geometryCollection.Count; j++)
{
    wkbTable.Rows.Add(geographyCollection[j].STAsBinary());
}

Note:

Definisci il tuo SqlParameter come segue:

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

Ho lasciato un SRID di 4326 dal mio lavoro di geografia. Puoi cambiarlo come preferisci, e in effetti se stai usando Geography Suggerirei di renderlo un secondo parametro per darti flessibilità.

Inoltre, se le prestazioni sono fondamentali, scoprirai che l'utilizzo di WKB è migliore. I miei test hanno rilevato che WKB è stato completato dal 45% al ​​65% del tempo impiegato da WKT. Questo varierà in base alla complessità dei tuoi dati e alla tua configurazione.

Le informazioni che hai trovato specificando il UdtTypeName del parametro come "Geometria" / "Geografia" è corretto quando la procedura memorizzata ha un parametro di tipo [Geometria] o [Geografia]. Non si applica ai TVP.