9

重複の可能性:
SQL レベルの関数を LINQ to Entity クエリで使用できるようにすることはできますか?

2 つのポイント間の距離を取得するスカラー関数があり、それを使用してポイントに最も近いレコードをクエリしたいと考えています。スカラー関数はlinq to sqlで機能しますが、EFでは失敗します

スカラー関数

USE [GeoData]
GO

/****** Object:  UserDefinedFunction [dbo].[DistanceBetween]    Script Date: 09/18/2012 19:40:44 ******/
SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO



CREATE FUNCTION [dbo].[DistanceBetween](@Lat1 as real,
@Long1 as real, @Lat2 as real, @Long2 as real)
RETURNS real
AS
BEGIN

DECLARE @dLat1InRad as float(53);
SET @dLat1InRad = @Lat1;
DECLARE @dLong1InRad as float(53);
SET @dLong1InRad = @Long1;
DECLARE @dLat2InRad as float(53);
SET @dLat2InRad = @Lat2;
DECLARE @dLong2InRad as float(53);
SET @dLong2InRad = @Long2 ;

DECLARE @dLongitude as float(53);
SET @dLongitude = @dLong2InRad - @dLong1InRad;
DECLARE @dLatitude as float(53);
SET @dLatitude = @dLat2InRad - @dLat1InRad;
/* Intermediate result a. */
DECLARE @a as float(53);
SET @a = SQUARE (SIN (@dLatitude / 2.0)) + COS (@dLat1InRad)
* COS (@dLat2InRad)
* SQUARE(SIN (@dLongitude / 2.0));
/* Intermediate result c (great circle distance in Radians). */
DECLARE @c as real;
SET @c = 2.0 * ATN2 (SQRT (@a), SQRT (1.0 - @a));
DECLARE @kEarthRadius as real;
/* SET kEarthRadius = 3956.0 miles */
SET @kEarthRadius = 6376.5;        /* kms */

DECLARE @dDistance as real;
SET @dDistance = @kEarthRadius * @c;
return (@dDistance);
END

GO

ado.net エンティティ モデルを追加し、データベースからモデルを更新して、distance between を選択しました。

 <Function Name="DistanceBetween" ReturnType="real" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="true" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
      <Parameter Name="Lat1" Type="real" Mode="In" />
      <Parameter Name="Long1" Type="real" Mode="In" />
      <Parameter Name="Lat2" Type="real" Mode="In" />
      <Parameter Name="Long2" Type="real" Mode="In" />
    </Function>

私は部分クラスを作り、このメソッドを書きました

public partial class GeoDataEntities
{
    [EdmFunction("GeoDataModel.Store", "DistanceBetween")]
    public double DistanceBetween(double lat1, double lon1, double lat2, double lon2)
    {
        throw new NotImplementedException();
    }
}

このコードで関数を何度もクエリしようとしましたが、エラーが発生します

var NParcel = db.geoAddresses.Where(g=> db.DistanceBetween(21.5,39.5, g.lat,g.lon) < 20);

NParcel に接続しようとするとcount、このエラーが発生しますforeach

タイプ 'EFSample.GeoDataEntities' で指定されたメソッド 'Double DistanceBetween(Double, Double, Double, Double)' は、LINQ to Entities ストア式に変換できません。

とスタックトレース

System.Data.Objects.ELinq.ExpressionConverter.ThrowUnresolvableFunction (式式) で System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.FunctionCallTranslator.TranslateFunctionCall (ExpressionConverter 親、MethodCallExpression 呼び出し、EdmFunctionAttribute functionAttribute) で System.Data.Objects.ELinq .ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter 親、MethodCallExpression linq) で System.Data.Objects.ELinq.ExpressionConverter.BinaryTranslator.TypedTranslate(ExpressionConverter 親、BinaryExpression linq) で System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(式 linq) System.Data.Objects.ELinq.ExpressionConverter.TranslateLambda (LambdaExpression ラムダ、DbExpression 入力) で System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter 親、MethodCallExpression 呼び出し、DbExpression& ソース、DbExpressionBinding& sourceBinding、DbExpression& ラムダ) System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter 親、MethodCallExpression 呼び出し) System.Data .Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter 親、MethodCallExpression linq) で System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq) で System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.AggregateTranslator.Translate( System.Data.Objects.ELinq.ExpressionConverter での ExpressionConverter 親、MethodCallExpression 呼び出し)。System.Data.Objects.ELinq.ExpressionConverter.Convert() の MethodCallTranslator.TypedTranslate (ExpressionConverter 親、MethodCallExpression linq) System.Data.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable)1 forMergeOption) at System.Data.Objects.ObjectQuery1.GetResults(Nullable 1 forMergeOption) at System.Data.Objects.ObjectQuery1.System.Collections.Generic.IEnumerable.GetEnumerator() at System.Linq.Enumerable.Single[TSource](IEnumerable 1 source) at System.Linq.Queryable.Count[TSource](IQueryable1 ソース)

4

1 に答える 1

25

方法は次のとおりです。

ステップ 1: edmx で

      <Function Name="DistanceBetween" Aggregate="false" BuiltIn="false" NiladicFunction="false" IsComposable="false" ParameterTypeSemantics="AllowImplicitConversion" Schema="dbo">
      <CommandText>
        select dbo.DistanceBetween(@lat1,@long1,@lat2,@long2)
      </CommandText>
      <Parameter Name="Lat1" Type="real" Mode="In" />
      <Parameter Name="Long1" Type="real" Mode="In" />
      <Parameter Name="Lat2" Type="real" Mode="In" />
      <Parameter Name="Long2" Type="real" Mode="In" />
    </Function>

ステップ 2: 関数をインポートする

  1. をダブルクリックedmx
  2. モデル ブラウザー ビューで、展開しGeoDataModel.Storeます (名前が異なる場合があります)。
  3. 拡大stored procedures /function
  4. ダブルクリックDistanceBetween
  5. Scalars = Single
  6. [OK] をクリックします。

ステップ 3: C# の場合:

    GeoDataEntities db = new GeoDataEntities();
    var first = db.DistanceBetween(234, 2342, 424, 243).First().Value;

いいえ、追加すること を忘れないでくださいIsComposable="false"ReturnType

      <CommandText>
        select dbo.DistanceBetween(@lat1,@long1,@lat2,@long2)
      </CommandText>

その助けを願って....

于 2012-09-19T19:36:06.843 に答える