如何基于经纬度距离计算方法对BO_MAGASIN列表进行排序
实现方案
你可以根据你的数据量选择以下两种方案:
方案1:内存中排序(适合小数据量场景)
基于你现有的距离计算方法,直接配合LINQ实现排序,步骤如下:
- 首先优化你现有的
CalculateDistance方法(原方法每次调用都创建数据库连接、拼接SQL存在注入风险、还有冗余查询,性能极低,建议替换为C#本地实现的Haversine公式计算经纬度距离):
// 优化后的本地距离计算方法,单位:公里 public double CalculateDistance(double baseLat, double baseLng, double targetLat, double targetLng) { const double EarthRadius = 6371; // 地球半径,单位公里 var latDiff = ToRadians(targetLat - baseLat); var lngDiff = ToRadians(targetLng - baseLng); var a = Math.Sin(latDiff / 2) * Math.Sin(latDiff / 2) + Math.Cos(ToRadians(baseLat)) * Math.Cos(ToRadians(targetLat)) * Math.Sin(lngDiff / 2) * Math.Sin(lngDiff / 2); var c = 2 * Math.Atan2(Math.Sqrt(a), Math.Sqrt(1 - a)); return EarthRadius * c; } // 角度转弧度辅助方法 private double ToRadians(double angle) { return angle * Math.PI / 180; } // 适配你原有入参的重载方法 public double CalculateDistance(string baseStoreId, BO_MAGASIN targetMag) { // 只查询一次基准点坐标,不要每次调用都查库 var baseMag = _context.Magasin.FirstOrDefault(x => x.storelocator_id.Equals(baseStoreId)); if (baseMag == null || targetMag == null) return double.MaxValue; // 注意把你存的字符串类型经纬度转成double if (!double.TryParse(baseMag.latitude, out var baseLat) || !double.TryParse(baseMag.longitude, out var baseLng) || !double.TryParse(targetMag.latitude, out var targetLat) || !double.TryParse(targetMag.longitude, out var targetLng)) { return double.MaxValue; } return CalculateDistance(baseLat, baseLng, targetLat, targetLng); }
- 拿到BO_MAGASIN列表后直接排序:
// 你的BO_MAGASIN列表 List<BO_MAGASIN> magasinList = GetYourMagasinList(); // 以storelocator_id为1的点为基准,按距离从近到远排序 var sortedList = magasinList.OrderBy(m => CalculateDistance("1", m)).ToList(); // 如果要从远到近就用OrderByDescending
方案2:数据库层面排序(适合大数据量场景,性能最优)
直接在查询列表的时候用MySQL自带的空间函数计算距离并排序,不需要把全量数据拉到内存处理:
public List<BO_MAGASIN> GetSortedMagasinList(string baseStoreId) { var baseMag = _context.Magasin.FirstOrDefault(x => x.storelocator_id.Equals(baseStoreId)); if (baseMag == null) return new List<BO_MAGASIN>(); string sql = @"SELECT * FROM magasin ORDER BY ST_Distance_Sphere(point(@baseLng, @baseLat), point(longitude, latitude))/1000 ASC"; string dbConn = configuration.GetSection("ConnectionStrings").GetSection("Default").Value; using var conn = new MySqlConnection(dbConn); conn.Open(); // 参数化查询避免SQL注入 var command = new MySqlCommand(sql, conn); command.Parameters.AddWithValue("@baseLat", double.Parse(baseMag.latitude)); command.Parameters.AddWithValue("@baseLng", double.Parse(baseMag.longitude)); using var reader = command.ExecuteReader(); var result = new List<BO_MAGASIN>(); while (reader.Read()) { // 填充BO_MAGASIN对象逻辑,和你原来获取列表的逻辑保持一致即可 result.Add(new BO_MAGASIN { storelocator_id = reader["storelocator_id"].ToString(), latitude = reader["latitude"].ToString(), longitude = reader["longitude"].ToString(), // 其他字段赋值 }); } return result; }
注意事项
- 原有的
CalculateDistance方法存在SQL注入风险、冗余查询、吞异常等问题,建议优先优化 - 如果你的经纬度字段存储类型是字符串,转换double的时候要做好异常处理,避免格式错误导致程序崩溃
内容的提问来源于stack exchange,提问作者user8065759
相关产品推荐
相关产品推荐

