3

私は次のコードを持っていました

query = query.Where(device => GetDeviceDistanceFromGeocode(geocode, device) <= distanceMetres);

private static double GetDeviceDistanceFromGeocode(Geocode geocode, Device device)
{
    return Math.Pow(
        Math.Pow(device.Address.Geocode.Easting - geocode.Easting, 2) +
        Math.Pow(device.Address.Geocode.Northing - geocode.Northing, 2)
        , 0.5);
}

ただし、linqが関数を認識できないため、例外がスローされ、クエリ式全体を一度に実行する必要があります。

Exception[LINQ to Entities does not recognize the method 
'Double DistanceOfDeviceFromGeocode(Geocode, Device)' method, 
and this method cannot be translated into a store expression.] 

ここでやろうとしているように、クエリ式を複数の部分に分割することは可能ですか?クエリが非常に大きい場合は、あまり読みやすくありません。


編集:

コメントで求められている完全なクエリは次のとおりです。

return query.Where(device => 
            Math.Pow(
                Math.Pow(device.Address.Geocode.Easting - geocode.Easting, 2) + 
                Math.Pow(device.Address.Geocode.Northing - geocode.Northing, 2)
                , 0.5) 
                <= distanceMetres);

基本的に、これはあまり読みやすいとは思わないので、複数の部分に分割したいと思いますが、提供されたリンクからは不可能と思われます。

C ++では、その一部をマクロに分割することもできましたが、残念ながら、これはc#の機能ではありません。


提案に従って、コードをこれに更新しました。これは非常にうまく機能し、コードの可読性を大幅に向上させます。

    return query.Where( DevicesWithinDistanceFromGeocode(distanceMetres, geocode) );
}

public Expression<Func<Device, bool>> DevicesWithinDistanceFromGeocode(double distance, Geocode geocode)
{
    return device => (  SqlFunctions.SquareRoot(
                            SqlFunctions.Square((double)(device.Address.Geocode.Easting - geocode.Easting)) +
                            SqlFunctions.Square((double)(device.Address.Geocode.Northing - geocode.Northing))
                        ) <= distance );
}
4

4 に答える 4

2

技術的にはそれを行う方法がありますが、LinqはカスタムコードをSQLに直接変換できないため、すべての結果をLinqに返し、カスタムメソッドを評価する必要があります。

これをWhere句で使用しているので、比較的少数のレコードを取得することを期待していると思います。その場合、ストアドプロシージャまたはスカラー値関数のいずれかで、SQLで条件をコーディングしてから、Linq-to-Entitiesクエリでそのsproc/関数を使用することをお勧めします。

于 2012-10-10T15:08:15.397 に答える
1

私はあなたが何をしているのかよくわかりません。このコードを1つの場所でのみ使用していて、それがクエリ内の唯一の句である場合、計算を別のメソッドに移動しても、実際にはそれほど変わりません。

代わりに、距離計算コードを複数の場所で再利用することを検討していて、それを繰り返したくない場合、または1つのクエリで呼び出したいチェックが多数あり、そのクエリを取得したくない場合扱いにくい、あなたは例えば試すことができます

public static IQueryable<Device> WhereCloseToGeocode(
    this IQueryable<Device> source,
    Geocode geocode,
    double distanceMetres)
{
    return source.Where(device => Math.Pow(
        Math.Pow(device.Address.Geocode.Easting - geocode.Easting, 2) +
        Math.Pow(device.Address.Geocode.Northing - geocode.Northing, 2),
        0.5) <= distanceMetres);  
}

public static IQueryable<Device> OtherCondition(
    this IQueryable<Device> source, ...)
{
   ...
}


...
devices = devices
    .WhereCloseToGeocode(geocode1, 3)
    .WhereCloseToGeocode(geocode2, 7)
    .OtherCondition(...);

距離の計算を独自の方法にするほど良くはありません。たとえば、「より近い」には1つの方法が必要で、「より遠い」には別の方法が必要ですが、L2Eでは基本的に同じであるため機能するはずWhereです。あなたが言うあなたの元の節を連鎖させることはうまくいく。

于 2012-10-10T15:43:43.673 に答える
0

問題は、deviceメソッドでを使用していることです。Linq to Entitiesは、LinqqueryをSQLQueryに変換する必要があります。

deviceこのクエリを成功させるには、最初にデータベースからすべてを選択する必要があります。

静的クラスSqlMethodsを調べて、この問題の他の例を見つけてください:)

于 2012-10-10T15:04:01.123 に答える
0

これは(テーブルのサイズによっては)非常に高額になる可能性がありますが、機能します。

query = query.ToList().Where(device => GetDeviceDistanceFromGeocode(geocode, device) <= distanceMetres);

このアプローチでは、最初にクエリを評価してから、クライアント側のすべてのレコードに対してメソッドを実行します。

于 2012-10-10T15:09:18.220 に答える