包含SqlGeometry的数据表正在导致存储过程执行失败...为什么?

Datatable containing SqlGeometry is causing stored procedure execution to fail... Why?(包含SqlGeometry的数据表正在导致存储过程执行失败...为什么?)
本文介绍了包含SqlGeometry的数据表正在导致存储过程执行失败...为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试将一系列SqlGeometry值保存到SQL Server 2008数据库。

基本上我在SQL Server存储过程中有一个表类型,如下所示:

CREATE TYPE [dbo].[TableType_Example] AS TABLE
(
    [SpatialID] [bigint] NOT NULL,
    [RecordID] [bigint] NOT NULL,
    [geom] [geometry] NOT NULL
)

然后我用C#构建了一个DataTable,并像这样发送它:

public static bool SaveSpatialDataElements(long recordID, List<BOSpatial> featureList)
{
        //Setup features datatable
        DataTable dtFeatures = new DataTable();
        dtFeatures.Columns.Add("SpatialID", typeof(SqlInt64));
        dtFeatures.Columns.Add("RecordID", typeof(SqlInt64));
        dtFeatures.Columns.Add("geom", typeof(SqlGeometry));

        foreach(var curFeature in featureList)
        {
            object[] curRowObjects = new object[dtFeatures.Columns.Count];
            curRowObjects[0] = curFeature.SpatialID;
            curRowObjects[1] = recordID;

            using (var reader = new StringReader(curFeature.ToGML()))
            {
                using (var xmlreader = new XmlTextReader(reader))
                {
                    curRowObjects[2] = SqlGeometry.GeomFromGml(new SqlXml(xmlreader), 0);
                }
            }

            DataRow row = dtFeatures.NewRow();
            row.ItemArray = curRowObjects;
            dtFeatures.Rows.Add(row);
        }

        DbConn conn = new DbConn();
        conn.Connect();
        conn.ExecuteStoredProcedure(false, "USP_tblSpatialLocation_Update", recordID, dtFeatures);
        conn.Disconnect();

        return true;
    }

这适用于我的所有其他数据表,但此表包含SqlGeometry列,并显示错误消息:

在中发生了类型为‘System.ArgumentException’的异常 System.Data.dll,但未在用户代码中处理

附加信息:不支持列‘geom’的类型。 类型为"SqlGeometry"

这对我来说没有任何意义,因为我在文档中阅读的内容似乎支持该数据类型。

有什么想法吗?

编辑:

下面的评论和我链接的文章https://viswaug.wordpress.com/2008/09/29/inserting-spatial-data-in-sql-server-2008/似乎建议我需要将SqlGeometry的数据类型更改为SqlDbType.Udt。遗憾的是,由于我使用的是DataTable,因此无法定义UdtTypeName = "GEOMETRY";,因为这是在参数上设置的。

推荐答案

自从对您的问题发表简短评论以来,我有机会充分考虑了这些选项。目前(即使是尝试.NET 4.6和SQL 2014),在为DataTable定义列时,似乎不能将SqlGeographySqlGeometry设置为typeof()参数。为了绝对清楚,您可以在.NET中这样做,甚至可以填充它,但这样就不能将该表作为TVP传递给存储过程。

有两个选项。

选项1.以WKT格式传送值。

按如下方式定义您的表类型。

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

然后按如下方式定义您的存储过程。

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

按如下方式定义.NET数据表:

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

按如下方式填充:

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

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

选项2.以WKB格式传送值。

按如下方式定义您的表类型。

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

然后按如下方式定义您的存储过程。

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

按如下方式定义.NET数据表:

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

按如下方式填充:

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

备注:

按如下方式定义SqlParameter:

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

我在地理工作中留下了SRID 4326。您可以随心所欲地将其更改为-事实上,如果您正在使用Geography,我建议将其作为第二个参数来为您提供灵活性。

此外,如果性能很重要,您会发现使用WKB更好。我的测试发现,wkt在45%到65%的时间内完成了wkb。这将因数据的复杂性和设置的不同而不同。

当您的存储过程具有类型为[Geometry]或[Geography]的参数时,您在将参数的UdtTypeName指定为"Geometry"/"Geography"时找到的信息是正确的。它不适用于TVP。

这篇关于包含SqlGeometry的数据表正在导致存储过程执行失败...为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本站部分内容来源互联网,如果有图片或者内容侵犯您的权益请联系我们删除!

相关文档推荐

DispatcherQueue null when trying to update Ui property in ViewModel(尝试更新ViewModel中的Ui属性时DispatcherQueue为空)
Drawing over all windows on multiple monitors(在多个监视器上绘制所有窗口)
Programmatically show the desktop(以编程方式显示桌面)
c# Generic Setlt;Tgt; implementation to access objects by type(按类型访问对象的C#泛型集实现)
InvalidOperationException When using Context Injection in ASP.Net Core(在ASP.NET核心中使用上下文注入时发生InvalidOperationException)
LINQ many-to-many relationship, how to write a correct WHERE clause?(LINQ多对多关系,如何写一个正确的WHERE子句?)