2012-10-11 165 views
20

我一个应用程序,我需要得到附近的地点工作最接近的位置, 我的web服务将接收2个参数(十进制经度,数字纬度)查找经度和纬度

我有一个表,其中位置被保存在经度和纬度字段的数据库中,

我想检索最近的位置。

任何人都可以帮忙吗?

这是我的代码:

var locations = from l in locations 

    select l 

以下是有关这个进一步的细节: 我有一个2名的字段(十进制(18,2)空)1个纬度,一个数据库表内2经度,

和我有一个方法

public List<Locations> GetLocation(decimal? Long, decimal? lat) 
{ 
var Loc = from l in Locations 
    //// now here is how to get nearest location ? how to query? 
    //// i have also tried Math.Abs(l.Lat - lat) its giving error about nullable decimal always hence i have seted decimal to nullable or converted to nullable 
//// also i have tried where (l.lat - Lat) * (l.lon - Long) this is also giving error about can not convert decimal to bool 
return Loc.ToList(); 
} 
+0

代码?非常简短......你有什么尝试过的吗? – lboshuizen

回答

4

这里是解决方案

var constValue = 57.2957795130823D 

var constValue2 = 3958.75586574D; 

var searchWithin = 20; 

double latitude = ConversionHelper.SafeConvertToDoubleCultureInd(Latitude, 0), 
        longitude = ConversionHelper.SafeConvertToDoubleCultureInd(Longitude, 0); 
var loc = (from l in DB.locations 
let temp = Math.Sin(Convert.ToDouble(l.Latitude)/constValue) * Math.Sin(Convert.ToDouble(latitude)/constValue) + 
           Math.Cos(Convert.ToDouble(l.Latitude)/constValue) * 
           Math.Cos(Convert.ToDouble(latitude)/constValue) * 
           Math.Cos((Convert.ToDouble(longitude)/constValue) - (Convert.ToDouble(l.Longitude)/constValue)) 
          let calMiles = (constValue2 * Math.Acos(temp > 1 ? 1 : (temp < -1 ? -1 : temp))) 
          where (l.Latitude > 0 && l.Longitude > 0) 
          orderby calMiles 

select new location 
    { 
    Name = l.name 
    }); 
    return loc .ToList(); 
+0

方式太多代码 – cyclical

+1

什么是常量值? –

+0

当前上下文中不存在名称“ConversionHelper”doest。 ,怎么解决? –

2

你有一个有效的范围内,在其外侧“打”是不是真的有关?如果是,请使用

from l in locations where ((l.lat - point.lat) * (l.lat - point.lat)) + ((l.lng - point.lng) * (l.lng - point.lng)) < (range * range) select l 

然后在这些结果的循环内找到具有最小平方距离值的命中。

+0

我不认为欧几里得距离比较适用于经度/纬度。 – Fung

+0

对于小范围(

+0

lat和longs不是正方形,可能在赤道附近,但不在其他地方... – sasjaq

44

您可以先将数据库中的位置数据转换为System.Device.Location.GeoCoordinate,然后使用LINQ找到最近的一个。

var coord = new GeoCoordinate(latitude, longitude); 
var nearest = locations.Select(x => new GeoCoordinate(x.Latitude, x.Longitude)) 
         .OrderBy(x => x.GetDistanceTo(coord)) 
         .First(); 
+2

+1好找!我不得不添加对'System.Device'的引用,但是效果很好!不错的代码谢谢! –

+0

明智的答案,这。 +1。 –

+1

位置是否需要在内存中?换句话说:是否可以在纯Linq-To-Entities(转换为SQL)中执行此操作? – sports

2

通过@Fung,为了详细说明注释如果您正在使用实体框架/ LINQ到实体,如果你尝试使用GeoCoordinate.GetDistanceTo方法在LINQ查询,你会得到一个运行时NotSupportedException异常与消息:

LINQ到实体无法识别方法“双GetDistanceTo(System.Device.Location.GeoCoordinate)”的方法,而这种方法不能被翻译成店表达。

使用实体框架版本5或6,替代方法是使用System.Data.Spatial.DbGeography类。例如:

DbGeography searchLocation = DbGeography.FromText(String.Format("POINT({0} {1})", longitude, latitude)); 

var nearbyLocations = 
    (from location in _context.Locations 
    where // (Additional filtering criteria here...) 
    select new 
    { 
     LocationID = location.ID, 
     Address1 = location.Address1, 
     City = location.City, 
     State = location.State, 
     Zip = location.Zip, 
     Latitude = location.Latitude, 
     Longitude = location.Longitude, 
     Distance = searchLocation.Distance(
      DbGeography.FromText("POINT(" + location.Longitude + " " + location.Latitude + ")")) 
    }) 
    .OrderBy(location => location.Distance) 
    .ToList(); 

_context在本例中是您先前实例化的DbContext实例。

虽然它现在是undocumented in MSDN,但DbGeography.Distance方法返回的单位看起来是米。参见:System.Data.Spatial DbGeography.Distance units?

1
var objAllListing = (from listing in _listingWithLanguageRepository.GetAll().Where(z => z.IsActive == true) 
            let distance = 12742 * SqlFunctions.Asin(SqlFunctions.SquareRoot(SqlFunctions.Sin(((SqlFunctions.Pi()/180) * (listing.Listings.Latitude - sourceLatitude))/2) * SqlFunctions.Sin(((SqlFunctions.Pi()/180) * (listing.Listings.Latitude - sourceLatitude))/2) + 
                 SqlFunctions.Cos((SqlFunctions.Pi()/180) * sourceLatitude) * SqlFunctions.Cos((SqlFunctions.Pi()/180) * (listing.Listings.Latitude)) * 
                 SqlFunctions.Sin(((SqlFunctions.Pi()/180) * (listing.Listings.Longitude - sourceLongitude))/2) * SqlFunctions.Sin(((SqlFunctions.Pi()/180) * (listing.Listings.Longitude - sourceLongitude))/2))) 
            where distance <= input.Distance 

            select new ListingFinalResult { ListingDetail = listing, Distance = distance }).ToList();//.Take(5).OrderBy(x => x.distance).ToList();