如何使用标量值函数使用LINQ到实体? [英] How to use scalar-valued function with linq to entity?
问题描述
可能重复:结果
的可以在SQL级别的功能提供给LINQ到实体的查询?
块引用>
我有一个标量函数,得到两点之间的距离,我想用它来查询记录最接近点。
标量函数使用LINQ工程SQL,但无法与EF
标量函数
使用[地理数据]
GO
/ ******对象:UserDefinedFunction [DBO] [DistanceBetween]脚本日期:2012年9月18日19时40分44秒****** /
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE FUNCTION [DBO]。[DistanceBetween](@ LAT1以假乱真,
@ Long1以假乱真,@ LAT2以假乱真,@ Long2以假乱真)
RETURNS真正的
AS
BEGIN
DECLARE @ dLat1InRad为float(53);
SET @ dLat1InRad = @ LAT1;
DECLARE @ dLong1InRad为float(53);
SET @ dLong1InRad = @ Long1;
DECLARE @ dLat2InRad为float(53);
SET @ dLat2InRad = @ LAT2;
DECLARE @ dLong2InRad为float(53);
SET @ dLong2InRad = @ Long2;
DECLARE @dLongitude为float(53);
设置@dLongitude = @ dLong2InRad - @ dLong1InRad;
DECLARE @dLatitude为float(53);
设置@dLatitude = @ dLat2InRad - @ dLat1InRad;
/ *中间结果。 * /
DECLARE @a为float(53);
设置@a = SQUARE(SIN(@dLatitude / 2.0))+ COS(@ dLat1InRad)
* COS(@ dLat2InRad)
* SQUARE(SIN(@dLongitude / 2.0));
/ *中间结果C(弧度大圈的距离)。 * /
DECLARE @c为实;
设置@c = 2.0 * ATN2(SQRT(@a),SQRT(1.0 - @a));
DECLARE @kEarthRadius以假乱真;
/ *设置kEarthRadius =3956.0英里* /
设置@kEarthRadius = 6376.5; / * *公里/
DECLARE @dDistance以假乱真;
设置@dDistance = @kEarthRadius * @c;
回报(@dDistance);
端
GO
我添加了一个ado.net实体模型,更新从数据库模型,并选择distancebetween
<作用NAME =distanceBetween的返回类型=真正的集合= 假内置=假NiladicFunction =假IsComposable =真ParameterTypeSemantics =AllowImplicitConversion架构=DBO>
<参数名称=LAT1TYPE =真正的模式=在/>
<参数名称=Long1TYPE =真正的模式=在/>
<参数名称=LAT2TYPE =真正的模式=在/>
<参数名称=Long2TYPE =真正的模式=在/>
< /功能>
我做了一个局部类,并写了这个方法。
公共部分类GeoDataEntities
{
[EdmFunction(GeoDataModel.Store,DistanceBetween)]
公共双DistanceBetween(双LAT1,双lon1,双LAT2,双lon2)
{
抛出新NotImplementedException();
}
}
我试过很多次使用此代码查询功能但它得到一个错误
VAR NParcel = db.geoAddresses.Where(G => db.DistanceBetween(21.5,39.5, g.lat,g.lon)小于20);
当我尝试
计数
或的foreach
的NParcel我得到这个错误
指定的方法'双DistanceBetween(双人间,双人间人,双人,
双人间)'的类型'EFSample.GeoDataEntities'不能被翻译
到LINQ到实体店的表情。
块引用>
和堆栈跟踪
在
System.Data.Objects.ELinq.ExpressionConverter.ThrowUnresolvableFunction(表达式$ b在
System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.FunctionCallTranslator.TranslateFunctionCall $ b表达式)(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
System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter
父母,MethodCallExpression调用)。 TypedTranslate(ExpressionConverter
父母,MethodCallExpression LINQ)在
System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression(表达式
LINQ)在
System.Data.Objects.ELinq.ExpressionConverter .MethodCallTranslator.AggregateTranslator.Translate(ExpressionConverter
父母,MethodCallExpression调用)在
System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate(ExpressionConverter
父母,MethodCallExpression LINQ)在
System.Data.Objects.ELinq.ExpressionConverter.Convert()在
System.Data.Objects.ELinq.ELinqQueryState.GetExecutionPlan在
(可空1
1.GetResults(可空
forMergeOption) System.Data.Objects.ObjectQuery1
1.System.Collections.Generic.IEnumerable.GetEnumerator()
forMergeOption)在
System.Data.Objects.ObjectQuery
在System.Linq.Enumerable.Single [TSource](IEnumerable的1源)在
1源)
System.Linq.Queryable .Count之间[TSource](IQueryable的
块引用>
解决方案这里是你如何做到这一点:
第1步:在EDMX
<作用NAME =DistanceBetween集合=false的内置=假NiladicFunction =假IsComposable =假ParameterTypeSemantics =AllowImplicitConversion架构=DBO>
<&CommandText中GT;
选择dbo.DistanceBetween(@ LAT1,@ long1,@ LAT2,@ long2)
< /&CommandText中GT;
<参数名称=LAT1TYPE =真正的模式=在/>
<参数名称=Long1TYPE =真正的模式=在/>
<参数名称=LAT2TYPE =真正的模式=在/>
<参数名称=Long2TYPE =真正的模式=在/>
< /功能>
第2步:导入功能
- 双击
EDMX
- 在模型浏览器视图中,展开
GeoDataModel.Store
(可能被命名不同)
- 展开
存储过程/函数
- 双击
DistanceBetween
标量=单
- 单击确定
第3步:在C#中:
GeoDataEntities DB =新GeoDataEntities();
VAR第一= db.DistanceBetween(234,2342,424,243)。首先()值。
注意是
IsComposable =FALSE
并没有的返回类型
不要忘记添加:<&CommandText中GT;
选择dbo.DistanceBetween(@ LAT1,@ long1,@ LAT2,@ long2)
< /&CommandText中GT;
希望,帮助....
Possible Duplicate:
Can SQL level functions be made available to LINQ to Entity queries?I have a scalar function that gets the distance between two points and I want to use it to query closest record to point. The scalar function works with linq to sql but fails with EF
the scalar function
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
I added an ado.net entity model, updated the model from the database and chose distancebetween
<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>
I made a partial class and wrote this method
public partial class GeoDataEntities { [EdmFunction("GeoDataModel.Store", "DistanceBetween")] public double DistanceBetween(double lat1, double lon1, double lat2, double lon2) { throw new NotImplementedException(); } }
I tried many times to query the function with this code but it gets an error
var NParcel = db.geoAddresses.Where(g=> db.DistanceBetween(21.5,39.5, g.lat,g.lon) < 20);
when i try to
count
orforeach
the NParcel I get this errorThe specified method 'Double DistanceBetween(Double, Double, Double, Double)' on the type 'EFSample.GeoDataEntities' cannot be translated into a LINQ to Entities store expression.
and stacktrace
at System.Data.Objects.ELinq.ExpressionConverter.ThrowUnresolvableFunction(Expression Expression) at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.FunctionCallTranslator.TranslateFunctionCall(ExpressionConverter parent, MethodCallExpression call, 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(Expression linq) at System.Data.Objects.ELinq.ExpressionConverter.TranslateLambda(LambdaExpression lambda, DbExpression input) at System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate(ExpressionConverter parent, MethodCallExpression call, DbExpression& source, DbExpressionBinding& sourceBinding, DbExpression& lambda) at 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(Expression 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(Nullable
1 forMergeOption) at System.Data.Objects.ObjectQuery
1.GetResults(Nullable1 forMergeOption) at System.Data.Objects.ObjectQuery
1.System.Collections.Generic.IEnumerable.GetEnumerator() at System.Linq.Enumerable.Single[TSource](IEnumerable1 source) at System.Linq.Queryable.Count[TSource](IQueryable
1 source)
解决方案Here is how you do it:
Step 1: In 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>
step 2: Import the function
- double click the
edmx
- In the Model Browser view, expand
GeoDataModel.Store
(could be named different)- expand
stored procedures /function
- double click
DistanceBetween
Scalars = Single
- Click OK
Step 3: In C#:
GeoDataEntities db = new GeoDataEntities(); var first = db.DistanceBetween(234, 2342, 424, 243).First().Value;
note that
IsComposable="false"
and noReturnType
and dont forget to add the :<CommandText> select dbo.DistanceBetween(@lat1,@long1,@lat2,@long2) </CommandText>
Hope that help....
这篇关于如何使用标量值函数使用LINQ到实体?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!