我试过了:
var doctorPractise = from d in db.DoctorsPrivateClinics
where GetDistance(db, d)<1.0
select d;
但是这不起作用,GetDistance是一个本地函数,我没有得到一个例外但它似乎没有用,有什么想法吗? 谢谢
GetDistance是:
private double GetDistance(DBClassesDataContext db, DoctorsPrivateClinic docPra)
{
double distance=-1;
double longitude;
double latitude;
var city = from c in db.Cities
where c.Code == Convert.ToInt32(Request.QueryString["Area"])
select c;
foreach (var cit in city)//it will be just one row that will be found but I don't know how to express it without foreach
{
Calculations.GetLongitudeLatitudeGoogle getLongLat = new Calculations.GetLongitudeLatitudeGoogle();
getLongLat.GetLongitudeLatitude("", cit.Name, "", out longitude, out latitude);
distance = CalcualateDistance(Convert.ToDouble(docPra.PrivateClinic.Latitude), Convert.ToDouble(docPra.PrivateClinic.Longtitude), latitude, longitude);
}
return distance;
}
我想要实现的是计算地图上某个特定点(cit.Name)与私人诊所的位置之间的距离。已从Google地图中检索地图上特定点的经度和纬度。在我的查询中,我指定此距离必须小于1 Km
答案 0 :(得分:10)
问题是您的查询是由LINQ提供程序(EF / Linq2Sql?)转换为SQL的。它无法翻译任意.net方法。解决这个问题的唯一方法是在本地枚举整个集合,无需使用索引等数据库,还可能从数据库中获取网络IO的瓶颈。
如果这不是问题:
var doctorPractise = from d in db.DoctorsPrivateClinics.AsEnumerable()
where GetDistance(db, d)<1.0
select d;
否则,请考虑以可转换为SQL的术语重新构建查询。看到您的GetDistance
方法有助于我们为您提供帮助。
答案 1 :(得分:2)
正如上面提到的那样,添加db.DoctorsPrivateClinics.AsEnumerable()就解决了我的问题。在改进了一点之后我的功能就是解决方案:
double longitude=0;
double latitude=0;
var city = from c in db.Cities
where c.Code == Convert.ToInt32(Request.QueryString["Area"])
select c;
city = city.Take(1);//take the first value, that sould be the only value in this case
if (city.Count() == 0)
{
//hanlde error
}
else
{
City cit = city.First();
Calculations.GetLongitudeLatitudeGoogle getLongLat = new Calculations.GetLongitudeLatitudeGoogle();
getLongLat.GetLongitudeLatitude("", cit.Name, "", out longitude, out latitude);
}
var doctorPractise = from d in db.DoctorsPrivateClinics.AsEnumerable()//or .ToList()
where CalcualateDistance(Convert.ToDouble(d.PrivateClinic.Latitude), Convert.ToDouble(d.PrivateClinic.Longtitude), latitude, longitude)<5.0f
select d;
其中函数CalcualateDistance为:
{
/*
The Haversine formula according to Dr. Math.
http://mathforum.org/library/drmath/view/51879.html
dlon = lon2 - lon1
dlat = lat2 - lat1
a = (sin(dlat/2))^2 + cos(lat1) * cos(lat2) * (sin(dlon/2))^2
c = 2 * atan2(sqrt(a), sqrt(1-a))
d = R * c
Where
* dlon is the change in longitude
* dlat is the change in latitude
* c is the great circle distance in Radians.
* R is the radius of a spherical Earth.
* The locations of the two points in
spherical coordinates (longitude and
latitude) are lon1,lat1 and lon2, lat2.
*/
double dDistance = Double.MinValue;
double dLat1InRad = Lat1 * (Math.PI / 180.0);
double dLong1InRad = Long1 * (Math.PI / 180.0);
double dLat2InRad = Lat2 * (Math.PI / 180.0);
double dLong2InRad = Long2 * (Math.PI / 180.0);
double dLongitude = dLong2InRad - dLong1InRad;
double dLatitude = dLat2InRad - dLat1InRad;
// Intermediate result a.
double a = Math.Pow(Math.Sin(dLatitude / 2.0), 2.0) +
Math.Cos(dLat1InRad) * Math.Cos(dLat2InRad) *
Math.Pow(Math.Sin(dLongitude / 2.0), 2.0);
// Intermediate result c (great circle distance in Radians).
double c = 2.0 * Math.Asin(Math.Sqrt(a));
// Distance.
// const Double kEarthRadiusMiles = 3956.0;
const Double kEarthRadiusKms = 6376.5;
dDistance = kEarthRadiusKms * c;
return dDistance;
}
尽管这对我有用,但它并不是使用LINQ的有效方法。所以我搜索了一个更好的解决方案,即在T-SQL中重新编写我的函数,因此改进的解决方案是:
double longitude=0;
double latitude=0;
var city = from c in db.Cities
where c.Code == Convert.ToInt32(Request.QueryString["Area"])
select c;
city = city.Take(1);//take the first value, that should be the only value in this case
if (city.Count() == 0)
{
//hanlde error
}
else
{
City cit = city.First();
Calculations.GetLongitudeLatitudeGoogle getLongLat = new Calculations.GetLongitudeLatitudeGoogle();
getLongLat.GetLongitudeLatitude("", cit.Name, "", out longitude, out latitude);
}
var doctorPractise = from d in db.DoctorsPrivateClinics
where db.CalculateDistance(Convert.ToDouble(d.PrivateClinic.Latitude), Convert.ToDouble(d.PrivateClinic.Longtitude), latitude, longitude) < 5.0f
select d;
用T-SQL编写的函数是:
ALTER FUNCTION PublicSiteDBUser.CalculateDistance
(
@latitudeArea float(53),
@longitudeArea float(53),
@latitudePractise float(53),
@longitudePractise float(53)
)
RETURNS float(53)
AS
BEGIN
DECLARE @dDistance as float(53)=0
DECLARE @dLat1InRad as float(53)=0
DECLARE @dLong1InRad as float(53)=0
DECLARE @dLat2InRad as float(53)=0
DECLARE @dLong2InRad as float(53)=0
DECLARE @dLongitude as float(53)=0
DECLARE @dLatitude as float(53)=0
DECLARE @a as float(53)=0
DECLARE @c as float(53)=0
DECLARE @kEarthRadiusKms as float(53)=6376.5
SET @dLat1InRad = @latitudeArea * PI() / 180.0
SET @dLong1InRad= @longitudeArea * PI()/180.0
SET @dLat2InRad= @latitudePractise * PI()/180.0
SET @dLong2InRad= @longitudePractise * PI()/180.0
SET @dLongitude = @dLong2InRad - @dLong1InRad
SET @dLatitude = @dLat2InRad - @dLat1InRad
SET @a = POWER(SIN(@dLatitude/2.0), 2.0)+COS(@dLat1InRad)*COS(@dLat2InRad) * POWER (SIN(@dLongitude/2.0),2.0)
SET @c = 2.0*ASIN(SQRT(@a))
SET @dDistance = @kEarthRadiusKms * @c
RETURN @dDistance
END
答案 2 :(得分:1)
如果您使用了ef,有办法编写sql并将linq映射到它,但在最简单的情况下,您可以检索所有数据然后执行自定义函数:
var doctorPractise = from d in db.DoctorsPrivateClinics.ToList()
where GetDistance(db, d)<1.0
select d;
答案 3 :(得分:1)
使用Sql函数
var query = from it in db.items
let facilityLatitude = it.Latitude ?? 0
let facilityLongitude = it.Longitude ?? 0
let theta = ((lon - facilityLongitude) * Math.PI / 180.0)
let requestLat = (lat * Math.PI / 180.0)
let facilityLat = (facilityLatitude * Math.PI / 180.0)
let dist = (SqlFunctions.Sin(requestLat) * SqlFunctions.Sin(facilityLat)) + (SqlFunctions.Cos(requestLat) * SqlFunctions.Cos(facilityLat) * SqlFunctions.Cos(theta))
let cosDist = SqlFunctions.Acos(dist)
let degDist = (cosDist / Math.PI * 180.0)
let absoluteDist = degDist * 60 * 1.1515
let distInKM = absoluteDist * 1.609344
where distInKM < distance
select new ()
{
Address = it.Address,
};