在ASP.NET Core 2与Entity Framework Core 2中实现附近位置查询
嘿,我完全懂你在ASP.NET Core里搞地理查询的头疼——DbGeography确实没法直接用,但咱们有俩靠谱的法子,能轻松找出目标经纬度50英里范围内的帖子,来一步步看:
方案1:用SQL Server内置地理类型(如果你用的是SQL Server)
如果你的数据库是SQL Server,直接用它自带的GEOGRAPHY类型来计算距离最省心,EF Core可以直接调用这些SQL函数:
- 先确认你的Post表中,
Longitude和Latitude是float或者decimal类型的字段 - 用
FromSqlRaw写原生SQL查询,示例代码如下:
// 替换成你的目标经纬度 var targetLat = 40.7128; var targetLon = -74.0060; const int maxDistanceMiles = 50; var nearbyPosts = await _context.Posts .FromSqlRaw(@" SELECT * FROM Posts WHERE GEOGRAPHY::Point(Latitude, Longitude, 4326) .STDistance(GEOGRAPHY::Point({0}, {1}, 4326)) / 1609.34 <= {2}", targetLat, targetLon, maxDistanceMiles) .ToListAsync();
小提示:GEOGRAPHY::Point的第三个参数4326是全球通用的WGS84 GPS坐标系,别乱改;STDistance返回的单位是米,除以1609.34就能转换成英里。
方案2:用Haversine公式手动计算(适配绝大多数数据库)
如果你的数据库不是SQL Server,或者不想依赖数据库的空间函数,用经典的Haversine公式计算球面距离就很稳妥,EF Core能把这个LINQ表达式转换成对应的SQL:
var targetLat = 40.7128; var targetLon = -74.0060; const int maxDistanceMiles = 50; const double earthRadiusMiles = 3956; // 地球的平均半径(英里) var nearbyPosts = await _context.Posts .Where(post => earthRadiusMiles * 2 * Math.Asin( Math.Sqrt( Math.Pow(Math.Sin((targetLat - post.Latitude) * Math.PI / 180 / 2), 2) + Math.Cos(targetLat * Math.PI / 180) * Math.Cos(post.Latitude * Math.PI / 180) * Math.Pow(Math.Sin((targetLon - post.Longitude) * Math.PI / 180 / 2), 2) ) ) <= maxDistanceMiles ) .ToListAsync();
关键注意事项:
- 索引优化:如果你的Post表数据量很大,一定要给
Longitude和Latitude字段加普通索引;如果用SQL Server的空间类型,还可以创建空间索引,能大幅提升查询速度 - 别搞反坐标:确保
Longitude是经度(范围-180180),`Latitude`是纬度(范围-9090),搞反的话距离计算完全错误 - 单位适配:如果需要换成公里,把地球半径改成6371,maxDistance换成公里数就行
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

