1

Nerddinner と同じ "distance between" 関数を実装しました。私は空港リポジトリを作成し、これらのメソッドを持っています:

    public IQueryable<AllAirports> ReturnAllAirportWithIn50milesOfAPoint(double lat, double lon)
    {
        var airports = from d in im.AllAirports
               where DistanceBetween(lat, lon, (double)d.Lat, (double)d.Lon) < 1000.00
               select d;
        return airports;
    }

    [EdmFunction("AirTravelModel.Store", "DistanceBetween")]
    public static double DistanceBetween(double lat1, double long1, double lat2, double long2)
    {
        throw new NotImplementedException("Only call through LINQ expression");
    }

テストしたところ、次のように表示されました。

base {"型 'AirTravelMVC3.Models.Repository.AirportRepository' の指定されたメソッド 'Double DistanceBetween(Double, Double, Double, Double)' は、渡された引数に一致するオーバーロードがないため、LINQ to Entities ストア式に変換できません。" } System.SystemException {System.NotSupportedException}

なぜこれが起こるのかについて何か考えはありますか?私の作品と nerddinner の唯一の違いは、エンティティ フレームワークで POCO プラグインを使用したことです。

SQL UDF は次のとおりです。データベースで非常にうまく機能します。

CREATE FUNCTION [dbo].[DistanceBetween](@Lat1 を実数として、
@Long1 は実数、@Lat2 は実数、@Long2 は実数)
実数を返します
なので
始める

DECLARE @dLat1InRad as float(53);
SET @dLat1InRad = @Lat1 * (PI()/180.0);
@dLong1InRad を float(53) として宣言します。
SET @dLong1InRad = @Long1 * (PI()/180.0);
DECLARE @dLat2InRad as float(53);
SET @dLat2InRad = @Lat2 * (PI()/180.0);
@dLong2InRad を float(53) として宣言します。
SET @dLong2InRad = @Long2 * (PI()/180.0);

DECLARE @dLongitude as float(53);
SET @dLongitude = @dLong2InRad - @dLong1InRad;
DECLARE @dLatitude as float(53);
SET @dLatitude = @dLat2InRad - @dLat1InRad;
/* 中間結果 a. */
DECLARE @a as float(53);
SET @a = SQUARE (SIN (@dLatitude / 2.0)) + COS (@dLat1InRad)
* COS (@dLat2InRad)
* SQUARE(SIN (@dLongitude / 2.0));
/* 中間結果 c (ラジアンでの大円距離)。*/
@c を実数として宣言します。
SET @c = 2.0 * ATN2 (SQRT (@a), SQRT (1.0 - @a));
@kEarthRadius を実数として宣言します。
/* kEarthRadius を設定 = 3956.0 マイル */
SET @kEarthRadius = 6376.5; /* キロ数 */

@dDistance を実数として宣言します。
SET @dDistance = @kEarthRadius * @c;
戻ります (@dDistance);
終わり
 
4

3 に答える 3

1

既存の NerdDinner ソースで POCO を使用してこれを行うには、これを DinnerRepository クラスに追加する必要がありました。

public IQueryable<Dinner> FindByLocation(float latitude, float longitude)
{
    List<Dinner> resultList = new List<Dinner>();

    var results = db.Database.SqlQuery<Dinner>("SELECT * FROM Dinners WHERE EventDate >= {0} AND dbo.DistanceBetween({1}, {2}, Latitude, Longitude) < 1000", DateTime.Now, latitude, longitude);
    foreach (Dinner result in results)
    {
        resultList.Add(db.Dinners.Where(d => d.DinnerID == result.DinnerID).FirstOrDefault());
    }

    return resultList.AsQueryable<Dinner>();
}
于 2011-07-07T14:12:25.740 に答える
0

DistanceBetween が c# で実装されていると仮定すると、(@p.campbell によって示唆されているように) 問題は、クエリ ジェネレーターが DistanceBetween の計算方法を認識していないことです。

コードをそのまま機能させるには、次のようなことが必要になる場合があります

public IQueryable<AllAirports> ReturnAllAirportWithIn50milesOfAPoint(double lat, double lon)
{
    var airports = from d in im.AllAirports.ToList()
           where DistanceBetween(lat, lon, (double)d.Lat, (double)d.Lon) < 1000.00
           select d;
    return airports;
}

ToList() は AllAirports を強制的にリストに評価し、C# 関数を使用してメモリ内で評価できます。明らかに、これは膨大な数の空港には拡張できません。それが問題だった場合は、大まかな「ボックス」クエリを実行して、安価な正方形内式を実行して少数の空港を返し、ToList を実行し、distance between を呼び出して結果を絞り込むことをお勧めします。

于 2011-06-20T21:11:24.510 に答える