Sqlserver
 sql >> Base de données >  >> RDS >> Sqlserver

La table de données contenant SqlGeometry provoque l'échec de l'exécution de la procédure stockée... Pourquoi ?

Depuis que j'ai fait un bref commentaire sur votre question, j'ai eu la chance de jouer pleinement avec les options. Il semble qu'à l'heure actuelle (même en essayant .NET 4.6 et SQL 2014), vous ne pouvez pas définir SqlGeography OU SqlGeometry comme typeof() paramètre lors de la définition d'une colonne pour un DataTable . Pour une clarté absolue, vous pouvez le faire dans .NET et même le remplir, mais vous ne pouvez alors pas passer cette table en tant que TVP à une procédure stockée.

Il y a deux options.

Option 1. Transmettez la valeur au format WKT.

Définissez votre type de table comme suit.

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

Définissez ensuite votre procédure stockée comme suit.

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

Définissez votre DataTable .NET comme suit :

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

Remplissez-le comme suit :

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

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

Option 2. Transmettez la valeur au format WKB.

Définissez votre type de table comme suit.

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

Définissez ensuite votre procédure stockée comme suit.

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

Définissez votre DataTable .NET comme suit :

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

Remplissez-le comme suit :

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

Remarques :

Définissez votre SqlParameter comme suit :

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

J'ai laissé un SRID de 4326 dans mon travail de géographie. Vous pouvez changer cela comme vous le souhaitez - et en effet si vous utilisez Geography Je suggérerais d'en faire un deuxième paramètre pour vous donner de la flexibilité.

De plus, si les performances sont essentielles, vous trouverez mieux d'utiliser WKB. Mes tests ont révélé que WKB était terminé en 45% à 65% du temps pris par WKT. Cela variera en fonction de la complexité de vos données et de votre configuration.

Les informations que vous avez trouvées en spécifiant le UdtTypeName du paramètre comme "Geometry" / "Geography" est correct lorsque votre procédure stockée a un paramètre de type [Geometry] ou [Geography]. Cela ne s'applique pas aux TVP.