我想在一定距离内和某个年龄段之间返回数据库中的用户列表。数据库中的每个用户记录都有三个相关字段。 LastLocationLatitude,LastLocationLongitude和DateOfBirth。我为搜索传递的标准是MinAge,MaxAge和MaxDistance。我首先使用Entity Framework代码。我的查询看起来像这样
var filtered = _repository.GetItems()
.Where(s => DateUtils.AgeInRange(s.UserCreated.DateOfBirth, criteria.MinAge, criteria.MaxAge))
.Where(s => LocationUtils.DistanceInRange(currentLocationLat, currentLocationLon, s.UserCreated.LastLocationLat, s.UserCreated.LastLocationLon, criteria.MaxDistance));
return filtered;
这两个方法都是这个
public static bool AgeInRange(DateTime dob, int min, int max)
{
var now = DateTime.UtcNow;
var years = now.Year - dob.Year;
if (now > dob) years--;
return years >= min && years <= max;
}
public static bool DistanceInRange(double currentLatitude, double currentLongitude, double otherLatitude, double otherLongitude, int maxDistance)
{
return SphericalLawOfCosinesCalc(currentLatitude, currentLongitude, otherLatitude, otherLongitude) <= maxDistance;
}
private static int SphericalLawOfCosinesCalc(double currentLatitude, double currentLongitude, double otherLatitude, double otherLongitude)
{
var latOne = (Math.PI/180)*currentLatitude;
var latTwo = (Math.PI/180)*otherLatitude;
var lonOne = (Math.PI/180)*currentLongitude;
var lonTwo = (Math.PI/180)*otherLongitude;
var distance = Math.Acos(
Math.Sin(latOne) * Math.Sin(latTwo) +
Math.Cos(latOne) * Math.Cos(latTwo) * Math.Cos(lonTwo - lonOne)
) * EarthsRadius;
return Convert.ToInt32(distance / 1.6);
}
现在在运行之前我知道它会抛出一个错误,说明LINQ-to-Entities不能识别方法AgeInRange()或DistanceInRange(),因为这些都是在服务器上执行的。我只是编写了这个来说明我想要实现的目标。
如果没有将这些方法中的每一个提取到一个野蛮且非常难看的内联语句中,有没有办法实现我想要实现的目标?显然我无法将整个列表返回到代码,转换为List然后进行过滤,因为每次搜索都会产生巨大的数据流量并且非常慢。
答案 0 :(得分:3)
只需使用现在在Entity Framework中实现的空间类型和查询即可。您将能够在数据库本身上运行空间计算,并且由于空间索引,您将获得更好的性能。
例如参见:http://kindohm.com/blog/2013/04/24/sql-spatial-search-demo.html