sql >> Base de Datos >  >> RDS >> Sqlserver

La tabla de datos que contiene SqlGeometry está causando que la ejecución del procedimiento almacenado falle... ¿Por qué?

Desde que hice un breve comentario sobre su pregunta, tuve la oportunidad de jugar completamente con las opciones. Parece que en la actualidad (incluso probando .NET 4.6 y SQL 2014) no puede configurar SqlGeography O SqlGeometry como el typeof() parámetro al definir una columna para un DataTable . Para una claridad absoluta, puede hacerlo en .NET e incluso completarlo, pero luego no puede pasar esa tabla como un TVP a un procedimiento almacenado.

Hay dos opciones.

Opción 1. Pasar el valor en formato WKT.

Defina su tipo de tabla de la siguiente manera.

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

Luego defina su procedimiento almacenado de la siguiente manera.

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 su tabla de datos .NET de la siguiente manera:

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

Rellénelo de la siguiente manera:

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

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

Opción 2. Pasar el valor en formato WKB.

Defina su tipo de tabla de la siguiente manera.

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

Luego defina su procedimiento almacenado de la siguiente manera.

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 su tabla de datos .NET de la siguiente manera:

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

Rellénelo de la siguiente manera:

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

Notas:

Defina su SqlParameter de la siguiente manera:

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

Dejé un SRID de 4326 de mi trabajo de geografía. Puede cambiar esto a lo que desee, y de hecho si está usando Geography Sugeriría convertirlo en un segundo parámetro para darle flexibilidad.

Además, si el rendimiento es crítico, encontrará que usar WKB es mejor. Mis pruebas encontraron que WKB completó en 45% a 65% del tiempo que tomó WKT. Esto variará según la complejidad de sus datos y su configuración.

La información que encontró al especificar el parámetro UdtTypeName como "Geometría" / "Geografía" es correcto cuando su Procedimiento almacenado tiene un parámetro de tipo [Geometría] o [Geografía]. No se aplica a los TVP.