如何使用带有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(Nullable1 forMergeOption) at System.Data.Objects.ObjectQuery
)System.Linq.Enumerable.Single [TSource](IEnumerable1 source) at System.Linq.Queryable.Count[TSource](IQueryable
1 source)
这是你如何做到的:
第1步:在edmx中
select dbo.DistanceBetween(@lat1,@long1,@lat2,@long2)
第2步:导入function
- 双击
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
,也不要忘记添加:
select dbo.DistanceBetween(@lat1,@long1,@lat2,@long2)
希望有帮助….