我有一个标量函数,它获取两点之间的距离,我想用它来查询最接近点的记录。标量函数与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实体模型,从数据库中更新了模型,并选择了
<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);
当我尝试count或foreachNParcel时出现此错误
count
foreach
类型为’EFSample.GeoDataEntities’的指定方法’Double DistanceBetween(Double,Double,Double,Double)’无法转换为LINQ to Entities存储表达式。
和stacktrace
在System.Data.Objects.ELinq.ExpressionConverter.ThrowUnresolvableFunction(Expression Expression)处System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.FunctionCallTranslator.TranslateFunctionCall(ExpressionConverter parent,MethodCallExpression call,EdmFunctionAttribute functionAttribute)在System.Data.Objects.ELinq System.Data.Objects.ELinq.ExpressionConverter.BinaryTranslator.TypedTranslate(ExpressionConverter父代,BinaryExpression linq)在System.Data.Objects.ELinq.ExpressionConion(Expression)(ExpressionConverter。在System.Data.Objects.ELinq处,位于System.Data.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda,DbExpression输入)处。ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter父,MethodCallExpression调用,DbExpression&源,DbExpressionBinding&sourceBinding,DbExpression&lambda)位于System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter .Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter父类,System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)在System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.AggregateTranslator。在System.Data.Objects.ELinq.ExpressionConverter处调用ExpressionConverter的父方法(调用MethodCallExpression)。System.Data.Objects.ELinq.ExpressionConverter.Convert()(System.Data.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable)处的MethodCallTranslator.TypedTranslate(ExpressionConverter parent,MethodCallExpression linq)1 forMergeOption) at System.Data.Objects.ObjectQuery1.GetResults(Nullable,1 forMergeOption) at System.Data.Objects.ObjectQuery位于System.Linq.Enumerable.Single [TSource]中的System.Collections.Generic.IEnumerable.GetEnumerator()(IEnumerable 1 source) at System.Linq.Queryable.Count[TSource](IQueryable1源)
1 forMergeOption) at System.Data.Objects.ObjectQuery
1 source) at System.Linq.Queryable.Count[TSource](IQueryable
这是您的操作方式:
第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:导入功能
edmx
GeoDataModel.Store
stored procedures /function
DistanceBetween
Scalars = Single
步骤3:在C#中:
GeoDataEntities db = new GeoDataEntities(); var first = db.DistanceBetween(234, 2342, 424, 243).First().Value;
请注意 , IsComposable="false"不ReturnType,不要忘记添加:
IsComposable="false"
ReturnType
<CommandText> select dbo.DistanceBetween(@lat1,@long1,@lat2,@long2) </CommandText>
希望能有所帮助。