如何使用带有linq的标量值函数实体?

可能重复:
LINQ to Entity查询可以使用SQL级别函数吗?

我有一个标量函数,可以获得两点之间的距离,我想用它来查询最近的记录到点。 标量函数与linq一起使用到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实体模型,从数据库更新模型并选择了距离

        

我做了一个部分类并编写了这个方法

 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或预测NParcel时,我得到了这个错误

“EFSample.GeoDataEntities”类型的指定方法“Double DistanceBetween(Double,Double,Double,Double)”无法转换为LINQ to Entities存储表达式。

和堆栈跟踪

System.Data.Objects.ELinq上的System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.FunctionCallTranslator.TranslateFunctionCall(ExpressionConverter parent,MethodCallExpression call,EdmFunctionAttribute functionAttribute)中的System.Data.Objects.ELinq.ExpressionConverter.ThrowUnresolvableFunction(Expression Expression) System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq)上的System.Data.Objects.ELinq.ExpressionConverter.BinaryTranslator.TypedTranslate(ExpressionConverter parent,BinaryExpression linq)中的.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent,MethodCallExpression linq)在System.Data.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda,DbExpression输入)处于System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent,MethodCallExpression call,DbExpression&source,DbExpressionBinding&sourceBinding,DbExpressio) n&lambda)在System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent,MethodCallExpression call)处于System的System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter parent,MethodCallExpression linq)。 System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate的System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.AggregateTranslator.Translate(ExpressionConverter parent,MethodCallExpression call)中的Data.Objects.ELinq.ExpressionConverter.TranslateExpression(Expression linq) (ExpressionConverter parent,MethodCallExpression linq)System.Data.Objects.ELinq.ExpressionConverter.Convert()中的System.Data.Objects.ELinq.ELinqQueryState.GetExecutionPlan(Nullable 1 forMergeOption) at System.Data.Objects.ObjectQuery 1.GetResults( 1 forMergeOption) at System.Data.Objects.ObjectQuery 1.System.Collections.Generic.IEnumerable.GetEnumerator(Nullable 1 forMergeOption) at System.Data.Objects.ObjectQuery )System.Linq.Enumerable.Single [TSource](IEnumerable 1 source) at System.Linq.Queryable.Count[TSource](IQueryable 1 source)

这是你如何做到的:

第1步:在edmx中

    select dbo.DistanceBetween(@lat1,@long1,@lat2,@long2)       

第2步:导入function

  1. 双击edmx
  2. 在“模型浏览器”视图中,展开GeoDataModel.Store (可以命名为不同)
  3. 扩展stored procedures /function
  4. 双击DistanceBetween
  5. Scalars = Single
  6. 单击确定

第3步:在C#中:

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

请注意IsComposable="false"并且没有ReturnType ,也不要忘记添加:

   select dbo.DistanceBetween(@lat1,@long1,@lat2,@long2)  

希望有帮助….