NPGSQL:使用LWGEOMCOLLECTION类型调用的相关操作

时间:2015-02-10 16:06:41

标签: c# postgis npgsql

我有一个使用Npgsql获取PostGIS数据的查询。它的目的是取一个点(x,y坐标)并计算出那个(如果有的话)几何形状。对于数据库中的绝大多数几何,查询工作正常,但至少有一个我得到以下异常:

  

错误:XX000:使用LWGEOMCOLLECTION类型调用的相关操作。   这是不受支持的。

堆栈跟踪的顶部是:

  

[NpgsqlException(0x80004005):错误:XX000:关联操作调用   使用LWGEOMCOLLECTION类型。这是不受支持的。]
  Npgsql.d__0.MoveNext()+ 3160
  Npgsql.ForwardsOnlyDataReader.GetNextResponseObject(布尔清理)   +808 Npgsql.ForwardsOnlyDataReader.GetNextRow(Boolean clearPending)+308 Npgsql.ForwardsOnlyDataReader.Read()+47

所有几何都应该有效,因为我在任何不是ST_MakeValid上调用ST_IsValid并且当前没有ST_GeomFromKML返回false。几何图形是通过调用ST_AsGeoJSON创建的,并在地图上使用WMS通过GeoServer作为栅格图层渲染,或使用command.CommandText = "SELECT area_code FROM area WHERE ST_INTERSECTS(ST_SetSRID(ST_Point(:x, :y), 4326), shape) AND area_type_code = :typecode"; command.CommandType = CommandType.Text; var typeCodeParameter = new NpgsqlParameter { DbType = DbType.String, ParameterName = "typecode", Value = _typeCode }; var xParameter = new NpgsqlParameter { DbType = DbType.Double, ParameterName = "x", Value = _x }; var yParameter = new NpgsqlParameter { DbType = DbType.Double, ParameterName = "y", Value = _y }; command.Parameters.Add(typeCodeParameter); command.Parameters.Add(xParameter); command.Parameters.Add(yParameter); using (var reader = command.ExecuteReader()) { if (reader.Read()) area = new AreaBasic { Code = (string)reader["area_code"] }; } 作为矢量图层渲染,因此PostGIS数据似乎没问题。

有什么方法可以修改我的代码或数据来阻止这种情况发生?代码失败的部分是读者阅读的部分:

{{1}}

编辑:更多信息。在pgAdmin III中运行带有硬编码值的查询时会出现同样的错误,因此问题不是特定于Npgsql。

1 个答案:

答案 0 :(得分:8)

这是因为尝试在几何集合上调用相交或包含类型查询,即,您有点,线和多边形的混合(可能是多个)。

至少有几种可能的修复方法。第一个更简单,但似乎有点hacky,这只是简单地将输入几何缓冲为0,这将导致非多边形被删除,因此,在您的情况下,只需将command.commandText更改为

SELECT area_code FROM area WHERE ST_INTERSECTS(ST_SetSRID(ST_Point(:x, :y), 4326), 
ST_Buffer(shape, 0)) AND area_type_code = :typecode";

注意,这种方法通常可用于修复无效几何,具有自相交循环的几何等。

第二种方法是在形状字段上使用ST_Dump分割成单个几何图形,然后仅通过ST_GeometryType函数在实际查询中使用多边形。

SELECT area_code 
FROM 
  (SELECT area_code, (ST_Dump(area)).geom FROM area) poly  
WHERE ST_INTERSECTS(ST_SetSRID(ST_Point(:x, :y), 4326), poly.geom) 
AND ST_GeometryType(poly.geom) = 'ST_Polygon' 
OR ST_GeometryType(poly.geom) = 'ST_MultiPolygon'
AND area_type_code = :typecode";

这是未经测试的,因为我无法清楚地对您的数据进行测试,但这些方法在实践中有效。