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

时间:2012-09-18 17:14:33

标签: c# sql entity-framework linq-to-entities

  

可能重复:
  Can SQL level functions be made available to LINQ to Entity queries?

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

之间的距离
 <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);

当我尝试countforeach NParcel时,我收到此错误

  

指定的方法'Double DistanceBetween(Double,Double,Double,   无法翻译类型'EFSample.GeoDataEntities'上的'))   进入LINQ to Entities存储表达式。

和stacktrace

  

在   System.Data.Objects.ELinq.ExpressionConverter.ThrowUnresolvableFunction(表达式   表达式)   System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.FunctionCallTranslator.TranslateFunctionCall(ExpressionConverter   parent,MethodCallExpression调用,EdmFunctionAttribute   functionAttribute)at   System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter   parent,MethodCallExpression linq)at   System.Data.Objects.ELinq.ExpressionConverter.BinaryTranslator.TypedTranslate(ExpressionConverter   parent,BinaryExpression linq)at   System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(表达式   linq)at   System.Data.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression   lambda,DbExpression输入)at   System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter   parent,MethodCallExpression call,DbExpression&amp;资源,   DbExpressionBinding&安培; sourceBinding,DbExpression&amp; lambda)   System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter   parent,MethodCallExpression call)at   System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter   parent,MethodCallExpression linq)at   System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(表达式   linq)at   System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.AggregateTranslator.Translate(ExpressionConverter   parent,MethodCallExpression call)at   System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter   parent,MethodCallExpression linq)at   System.Data.Objects.ELinq.ExpressionConverter.Convert()at   System.Data.Objects.ELinq.ELinqQueryState.GetExecutionPlan(可空1 forMergeOption) at System.Data.Objects.ObjectQuery 1.GetResults(可空1 forMergeOption) at System.Data.Objects.ObjectQuery 1.System.Collections.Generic.IEnumerable.GetEnumerator()   在System.Linq.Enumerable.Single [TSource](IEnumerable 1 source) at System.Linq.Queryable.Count[TSource](IQueryable 1来源)

1 个答案:

答案 0 :(得分: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. 点击确定
  7. 第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>
    

    希望有帮助....