2012-10-11 160 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();