我有这个工作代码:
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数据库和代码优先方法。
答案 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映射方法应该可以。)