地理位置之间的Haversine LINQ距离

时间:2018-08-18 09:28:18

标签: c# sql-server linq geolocation haversine

我有这个工作代码:

IEnumerable<Message> dbCities = db.Cities;

dbCities = dbCities.Where(x => GetDistanceBetweenLocations(longitude, latitude, x.Longitude, x.Latitude) <= radius);

public int GetDistanceBetweenLocations(double lon1, double lat1, double lon2, double lat2)
{
        var sCoord = new GeoCoordinate(lon1, lat1);
        var eCoord = new GeoCoordinate(lon2, lat2);

        return Convert.ToInt32(Math.Round(sCoord.GetDistanceTo(eCoord)));
}

但是有点慢。我正在尝试在数据库中移动逻辑以提高性能。

我从几件事开始:

dbCities = db.Cities.Where(x => new GeoCoordinate(longitude, latitude).GetDistanceTo(new GeoCoordinate(x.Longitude, x.Latitude)) <= radius);

得到了:LINQ to Entities无法识别方法'Double GetDistanceTo(System.Device.Location.GeoCoordinate)',该方法无法转换为商店表达式。

我了解Haversine公式,但无法与linq配合使用。

该项目使用SQL Server数据库和代码优先方法。

1 个答案:

答案 0 :(得分:0)

错误消息说明了一切:EF的LINQ提供程序不知道如何将名为 GetDistanceTo 的函数映射到其SQL副本。

如果您希望任务由基础DBMS完成,则需要重写查询以仅使用canonical functions。另外,您可以将逻辑定义为数据库中的UDF(如果数据库引擎支持UDF)和introduce it to EF

但是,如果要在应用程序中处理此问题,可以将LINQ to Entites查询“强制”到LINQ to Objects中:

class

但是,要小心:使用这种方法,将从DB中提取每个城市记录,以供您的 GetDistanceTo 逻辑检查。

更新

从2012版开始,SQL Server提供了内置的地理API。它也可以calculate distances

您可以通过DbGeography class在EF中访问此API。看看this discussion

如果您使用EF Core,则需要一种变通办法,因为尚未迁移 DbGeography ,预计在version 2.2.0中使用。 (但是,前面提到的UDF映射方法应该可以。)