Sqlserver
 sql >> Datenbank >  >> RDS >> Sqlserver

Eine Datentabelle, die SqlGeometry enthält, führt dazu, dass die Ausführung einer gespeicherten Prozedur fehlschlägt ... Warum?

Seit ich einen kurzen Kommentar zu Ihrer Frage abgegeben habe, hatte ich Gelegenheit, mit den Optionen vollständig herumzuspielen. Es scheint, dass Sie derzeit (selbst wenn Sie .NET 4.6 und SQL 2014 versuchen) SqlGeography nicht festlegen können ODER SqlGeometry als typeof() Parameter beim Definieren einer Spalte für eine DataTable . Zur absoluten Klarheit können Sie dies in .NET tun und sogar füllen, aber Sie können diese Tabelle dann nicht als TVP an eine gespeicherte Prozedur übergeben.

Es gibt zwei Möglichkeiten.

Option 1. Übergeben Sie den Wert im WKT-Format.

Definieren Sie Ihren Tabellentyp wie folgt.

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

Definieren Sie dann Ihre gespeicherte Prozedur wie folgt.

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

Definieren Sie Ihre .NET DataTable wie folgt:

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

Füllen Sie es wie folgt aus:

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

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

Option 2. Übergeben Sie den Wert im WKB-Format.

Definieren Sie Ihren Tabellentyp wie folgt.

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

Definieren Sie dann Ihre gespeicherte Prozedur wie folgt.

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

Definieren Sie Ihre .NET DataTable wie folgt:

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

Füllen Sie es wie folgt aus:

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

Hinweise:

Definieren Sie Ihren SqlParameter wie folgt:

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

Ich habe eine SRID von 4326 aus meiner Geografiearbeit hinterlassen. Sie können dies nach Belieben ändern - und zwar, wenn Sie Geography verwenden Ich würde vorschlagen, es zu einem zweiten Parameter zu machen, um Ihnen Flexibilität zu geben.

Wenn die Leistung kritisch ist, werden Sie außerdem feststellen, dass die Verwendung von WKB besser ist. Meine Tests ergaben, dass WKB in 45 % bis 65 % der Zeit, die WKT benötigte, abgeschlossen wurde. Dies hängt von der Komplexität Ihrer Daten und Ihrer Einrichtung ab.

Die Informationen, die Sie bei der Angabe des UdtTypeName des Parameters gefunden haben als "Geometrie" / "Geographie" ist richtig, wenn Ihre gespeicherte Prozedur einen Parameter vom Typ [Geometrie] oder [Geographie] hat. Es gilt nicht für TVPs.