我有这个工作代码:
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 DB 和代码优先方法。
错误消息不言自明:EF 的 LINQ 提供程序不知道如何将名为GetDistanceTo的函数映射到其 SQL 副本。
如果您希望任务由底层 DBMS 完成,您需要重写您的查询以仅使用规范函数。或者,您可以将逻辑定义为数据库中的 UDF(如果您的数据库引擎支持 UDF)并将其引入 EF。
但是,如果您想在应用程序中处理此问题,您可以将您的 LINQ to Entites 查询“强制”到一个 LINQ to Objects 中:
dbCities = db.Cities.AsEnumerable().Where(x => new GeoCoordinate(longitude, latitude).GetDistanceTo(new GeoCoordinate(x.Longitude, x.Latitude)) <= radius);
但是,请注意这一点:使用这种方法,每个城市记录都将从数据库中获取,以供您的GetDistanceTo逻辑检查。
更新
从 2012 版开始,SQL Server 提供了一个内置的地理 API。它也可以计算距离。
您可以通过DbGeography 类在 EF 中访问此 API 。看看这个讨论。
如果您使用 EF Core,您需要一个解决方法,因为DbGeography尚未移植,预计在2.2.0 版中。(但是,前面提到的 UDF 映射方法应该可以工作。)
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句