sql >> Databasteknik >  >> RDS >> Sqlserver

Datatabell som innehåller SqlGeometry gör att exekvering av lagrad procedur misslyckas... Varför?

Sedan jag gjorde en kort kommentar till din fråga har jag haft chansen att leka med alternativen fullt ut. Det verkar som att du för närvarande (även om du försöker .NET 4.6 och SQL 2014) inte kan ställa in SqlGeography ELLER SqlGeometry som typeof() parameter när du definierar en kolumn för en DataTable . För absolut tydlighet kan du göra det i .NET och till och med fylla i det, men du kan sedan inte skicka den tabellen som en TVP till en lagrad procedur.

Det finns två alternativ.

Alternativ 1. Skicka värdet i WKT-format.

Definiera din tabelltyp enligt följande.

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

Definiera sedan din lagrade procedur enligt följande.

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

Definiera din .NET DataTable enligt följande:

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

Fyll i den enligt följande:

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

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

Alternativ 2. Skicka värdet i WKB-format.

Definiera din tabelltyp enligt följande.

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

Definiera sedan din lagrade procedur enligt följande.

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

Definiera din .NET DataTable enligt följande:

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

Fyll i den enligt följande:

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

Anmärkningar:

Definiera din SqlParameter enligt följande:

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

Jag har lämnat ett SRID på 4326 från mitt geografiarbete. Du kan ändra detta till vad du vill - och faktiskt om du använder Geography Jag skulle föreslå att du gör det till en andra parameter för att ge dig flexibilitet.

Dessutom, om prestandan är kritisk, kommer du att upptäcka att använda WKB bättre. Mina tester visade att WKB slutförde på 45 % till 65 % av tiden som WKT tog. Detta kommer att variera beroende på hur komplex dina data är och dina inställningar.

Informationen du hittade när du angav parameterns UdtTypeName som "Geometry" / "Geography" är korrekt när din lagrade procedur har en parameter av typen [Geometry] eller [Geography]. Det gäller inte TVP.



  1. find() på modellen ger id som sträng i en miljö och int i en annan

  2. Hur man säkert infogar kod i mySQL-databasen

  3. UDF-prestanda i MySQL

  4. Specialtecken i PHP/MySQL