用linq或亚音速计算距离

时间:2010-03-04 17:05:55

标签: c# asp.net linq google-maps subsonic3

我从搜索页面获得此MySQL语句,用户输入邮政编码,并在输入的邮政编码的15密耳内找到最近的stiocklist。

 SELECT *  , (
(
ACOS( SIN( "+SENTLNG +" * PI( ) /180 ) * SIN( s_lat * PI( ) /180 ) + COS( " + SENTLNG +" * PI( ) /180 ) * COS( s_lat * PI( ) /180 ) *  COS( (
" + SENTLANG + " - s_lng
) * PI( ) /180 ) ) *180 / PI( )
) *60 * 1.1515
) AS distance_miles
FROM new_stockists
WHERE s_lat IS NOT NULL
HAVING distance_miles <15
ORDER BY distance_miles ASC
LIMIT 0 , 15  

但现在我正在使用linq和亚音速,并没有弄清楚如何在linq或亚音速中做到这一点 你的帮助将不胜感激,也请注意,我不得不发送一个动态的地址,这就是页面顶部提到的邮政编码,我打电话给谷歌,然后获取lng和lat给他们的邮政编码给出

3 个答案:

答案 0 :(得分:2)

您可以在MS SQL中创建一个存储过程来执行查询所执行的操作,然后从您的应用程序中调用该查询。 Linq确实支持存储过程 - 有点像这样

partial class StockistsDataContext
{
    [Function(Name = "dbo.NewStockistsByDistance")]
    public ISingleResult<NewStockist> NewStockistsByDistance(
        [Parameter(DbType = "Int", Name = "s_lat")] int lat,
        [Parameter(DbType = "Int", Name = "s_lng")] int lng)
    {
        var result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), lat, lng);
        return ((ISingleResult<NewStockist>)(result.ReturnValue));
    }
}

回退到存储过程有点恼火,但我不认为解析Queryables表达式的Linq部分可以检测到revant数学函数并将它们映射到SQL。

答案 1 :(得分:0)

我建议(如果可能)获取邮政编码的中心点,然后应用Haversine公式查找特定半径范围内的所有商店。

此处的公式以千米为单位。
您必须更改相关数字,它才能行驶数英里。
例如:将6371.392896转换为里程。

宣布@radiusInKm为FLOAT DECLARE @ lat2Compare AS FLOAT
DECLARE @ long2Compare AS FLOAT
SET @radiusInKm = 5.000
SET @ lat2Compare = insert_your_lat_to_compare_here
SET @ long2Compare = insert_you_long_to_compare_here

SELECT * FROM insert_your_table_here WITH(NOLOCK) WHERE(6371.392896 * 2 * ATN2(SQRT((sin((弧度(GeoLatitude - @ lat2Compare))/ 2)* sin((弧度(GeoLatitude - @ lat2Compare))/ 2))+(cos(弧度(GeoLatitude)) * cos(弧度(@ lat2Compare))* sin(弧度(GeoLongitude - @ long2Compare)/ 2)* sin(弧度(GeoLongitude - @ long2Compare)/ 2))) ,SQRT(1 - ((sin((弧度(GeoLatitude - @ lat2Compare))/ 2)* sin((弧度(GeoLatitude - @ lat2Compare))/ 2))+(cos(弧度(GeoLatitude))* cos(弧度) (@ lat2Compare))* sin(弧度(GeoLongitude - @ long2Compare)/ 2)* sin(弧度(GeoLongitude - @ long2Compare)/ 2))) )))&lt; = @radiusInKm

如果您想在C#中执行Haversine公式,

double resultDistance = 0.0;
double avgRadiusOfEarth = 6371.392896; //地球的半径不同,我取平均值。

// Haversine公式
//距离= R * 2 * aTan2(A的平方根,1 - A的平方根)
//其中A =正方形平方(纬度差/ 2)+(纬度1的余弦值*纬度2 *正弦平方的余弦值(经度/ 2的差值))
//和R =地球的周长

double differenceInLat = DegreeToRadian(currentLatitude - latitudeToCompare);
double differenceInLong = DegreeToRadian(currentLongitude - longtitudeToCompare);
double aInnerFormula = Math.Cos(DegreeToRadian(currentLatitude))* Math.Cos(DegreeToRadian(latitudeToCompare))* Math.Sin(differenceInLong / 2)* Math.Sin(differenceInLong / 2);
double aFormula =(Math.Sin((differenceInLat)/ 2)* Math.Sin((differenceInLat)/ 2))+(aInnerFormula);
resultDistance = avgRadiusOfEarth * 2 * Math.Atan2(Math.Sqrt(aFormula),Math.Sqrt(1 - aFormula));

DegreesToRadian是我自定义创建的函数 它是“Math.PI * angle / 180.0”的简单1衬里

对于LINQ,您可以使用C#数学函数以及所有C#检查。例如:!=等于不等等。
请参阅以下示例 它不完整,所以请根据自己的喜好进行调整。

  

var linqQuery = from linqCollection in   insert_your_collection_here
                其中s_lat!=什么都没有                 选择Math.ACos(Math.Sin(DegreesToRadian(sentlng)   * Math.Pi / 180))

查看下面的MSDN链接,了解所有简单的LINQ示例。玩弄它,希望这有帮助

My blog entry - SQL Haversine

MSDN - 101 LINQ Samples

答案 2 :(得分:-1)

使用SQL的这一部分在SQL Server中创建一个新视图:

SELECT * , (your equation here) as distance
FROM new_stocklists
WHERE s_lat is not NULL

然后,您可以为视图创建Linq对象(SQLMetal将执行此操作或在Visual Studio中执行Linq to SQL)。然后,您可以使用Linq查询此视图。假设您的对象是StockDistance:

var list = db.StockDistance.Where(x=>x.distance<15)
    .OrderBy(x=>x.distance)
    .Take(15);