ASP.NET执行MySQL几何查询报st_geometryfromtext无效GIS数据错误
问题原因
你遇到的报错核心原因有两点:
- EF Core的
FromSqlRaw方法只会替换SQL语句中独立位置的{n}格式占位符,不会替换单引号包裹的字符串字面量内部的占位符。你当前代码把所有坐标占位符写在了'POLYGON((...))'的单引号内部,最终传给MySQL的SQL语句里,占位符根本没有被替换成实际坐标值,ST_GeomFromText拿到的是包含{0} {1}这类无效字符的WKT文本,自然会抛出无效GIS数据的异常。 - 你原本尝试用C#字符串拼接组装SQL的写法本身存在SQL注入风险,不符合原生查询的安全要求。
解决方案
以下两种写法都可以同时解决参数绑定失效和SQL注入防护的需求:
方案1:C#侧组装WKT单参数传入(写法最简洁)
因为经纬度本身是数值类型,只要先把传入的坐标参数校验为合法数值(经度范围-180180,纬度范围-9090),在C#侧组装成完整的POLYGON WKT字符串后作为单个参数传入即可,不要给参数加单引号,EF Core的参数化机制会自动处理转义:
// 经纬度参数提前做类型校验和范围校验,确保是合法数值 var polygonWkt = string.Format( "POLYGON(({0} {1}, {2} {3}, {4} {5}, {6} {7}, {8} {9}))", long1, lat1, long2, lat2, long3, lat3, long4, lat4, long1, lat1 ); List<Flight> result = await _context.Flight .FromSqlRaw(@"SELECT * FROM flight WHERE ST_Contains( ST_GeomFromText({0}), POINT(StartLongitude, StartLatitude) )", polygonWkt) .ToListAsync();
注意:不要用C#字符串插值直接写在
FromSqlRaw参数位(即FromSqlRaw($"SELECT...{polygonWkt}")),这种写法会在C#侧直接把值拼进SQL字符串,失去参数化防护能力。
方案2:SQL侧用CONCAT组装WKT(零字符串拼接风险)
如果不想在C#侧做字符串组装,可以用MySQL内置的CONCAT函数在SQL语句内部拼接WKT文本,所有坐标都作为独立数值参数传入,所有{n}占位符都放在单引号外部,EF Core可以正常识别绑定,彻底杜绝注入风险:
List<Flight> result = await _context.Flight .FromSqlRaw(@"SELECT * FROM flight WHERE ST_Contains( ST_GeomFromText(CONCAT( 'POLYGON((', {0}, ' ', {1}, ',', {2}, ' ', {3}, ',', {4}, ' ', {5}, ',', {6}, ' ', {7}, ',', {8}, ' ', {9}, '))' )), POINT(StartLongitude, StartLatitude) )", long1, lat1, long2, lat2, long3, lat3, long4, lat4, long1, lat1) .ToListAsync();
额外注意事项
- MySQL要求POLYGON类型的WKT文本首尾坐标必须完全一致,否则会被判定为无效几何数据,你的代码里已经做了首尾坐标复用,这点符合要求。
- 存储坐标的空间字段建议创建MySQL空间索引,ST_Contains类空间查询的性能会有数量级提升。
内容的提问来源于stack exchange,提问作者CR7
相关产品推荐
相关产品推荐

