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

7
我有一个查询,使用Npgsql获取PostGIS数据。它的目的是获取一个点(x,y坐标),并找出该点是否存在任何几何形状。对于数据库中绝大部分的几何形状,查询都可以正常工作,但至少有一种几何形状会导致以下异常:

ERROR: XX000: 应用了LWGEOMCOLLECTION类型的关联操作。这是不被支持的。

堆栈跟踪的顶部如下所示:

[NpgsqlException (0x80004005): ERROR: XX000: 应用了LWGEOMCOLLECTION类型的关联操作。这是不被支持的。]
Npgsql.d__0.MoveNext() +3160
Npgsql.ForwardsOnlyDataReader.GetNextResponseObject(Boolean cleanup) +808 Npgsql.ForwardsOnlyDataReader.GetNextRow(Boolean clearPending) +308 Npgsql.ForwardsOnlyDataReader.Read() +47

所有几何形状应该都是有效的,因为我会在任何无效的几何形状上调用ST_MakeValid,而目前没有任何ST_IsValid返回false的情况。该几何形状是通过调用ST_GeomFromKML创建的,并且在地图上以栅格图层(通过GeoServer使用WMS)或矢量图层(使用ST_AsGeoJSON)呈现,因此PostGIS数据似乎是正确的。
是否有任何方法可以修改我的代码或数据以防止发生这种情况?代码失败部分是读取reader的部分:
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"]
        };
}

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

1个回答

9
这是因为在Geometry Collection上尝试调用intersects或contains类型查询,即其中包含点、线和多边形的混合物。
至少有两种可能的修复方法。第一种方法更简单,但似乎有点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";

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接