2012-09-18 28 views
6

thể trùng lặp:
Can SQL level functions be made available to LINQ to Entity queries?Làm thế nào để sử dụng hàm vô hướng có giá trị với LINQ đối với thực thể?

Tôi có một hàm vô hướng mà được khoảng cách giữa hai điểm và tôi muốn sử dụng nó để truy vấn kỷ lục gần tới điểm. Các hàm vô hướng làm việc với LINQ to SQL nhưng không thành công với EF

các hàm vô hướng

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 

tôi đã thêm một mô hình ado.net entity, cập nhật mô hình từ cơ sở dữ liệu và chọn 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> 

tôi đã thực hiện một lớp học phần và viết phương pháp này

public partial class GeoDataEntities 
{ 
    [EdmFunction("GeoDataModel.Store", "DistanceBetween")] 
    public double DistanceBetween(double lat1, double lon1, double lat2, double lon2) 
    { 
     throw new NotImplementedException(); 
    } 
} 

tôi đã cố gắng nhiều lần để truy vấn các chức năng với mã này nhưng nó được một lỗi

var NParcel = db.geoAddresses.Where(g=> db.DistanceBetween(21.5,39.5, g.lat,g.lon) < 20); 

khi tôi cố gắng để count hoặc foreach các NParcel tôi nhận được lỗi này

Phương pháp xác định 'đúp DistanceBetween (Double, Double, Double, Double) 'trên loại' EFSample.GeoDataEntities 'không thể dịch được thành biểu thức lưu trữ LINQ to Entities.

và stacktrace

tại System.Data.Objects.ELinq.ExpressionConverter.ThrowUnresolvableFunction (Biểu Expression) tại System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.FunctionCallTranslator.TranslateFunctionCall (ExpressionConverter cha mẹ, gọi MethodCallExpression, EdmFunctionAttribute functionAttribute) tại System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate (ExpressionConverter phụ huynh, MethodCallExpression LINQ) tại System.Data.Objects.ELinq.ExpressionConverter.BinaryTranslator.TypedTranslate (ExpressionConverter phụ huynh, BinaryExpression LINQ) tại System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression (Biểu LINQ) tại Hệ thống .Data.Objects.ELinq.ExpressionConverter.TranslateLambda (LambdaExpression lambda, DbExpression đầu vào) tại System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate (ExpressionConverter phụ huynh, cuộc gọi MethodCallExpression, DbExpression & nguồn, DbExpressionBinding & sourceBinding, DbExpression & lambda) tại System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.OneLambdaTranslator.Translate (ExpressionConverter parent, MethodCallExpression call) tại System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate (ExpressionConverter phụ huynh, MethodCallExpression LINQ) tại System.Data.Objects.ELinq.ExpressionConverter.TranslateExpression (Biểu LINQ) tại System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.AggregateTranslator.Translate (ExpressionConverter phụ huynh, MethodCallExpression gọi) tại System.Data.Objects.ELinq.ExpressionConverter.MethodCallTranslator.TypedTranslate (ExpressionConverter phụ huynh, MethodCallExpression LINQ) tại System.Data.Objects.ELinq.ExpressionConverter.Convert() tại System.Data.Objects.ELinq. ELinqQueryState.GetExecutionPlan (Nullable 1 forMergeOption) at System.Data.Objects.ObjectQuery 1.GetResults (Nullable 1 forMergeOption) at System.Data.Objects.ObjectQuery 1.System.Collections.Generic.IEnumerable.GetEnume rator() tại System.Linq.Enumerable.Single [TSource] (IEnumerable 1 source) at System.Linq.Queryable.Count[TSource](IQueryable 1 nguồn)

+0

EF5 hỗ trợ kiểu dữ liệu không gian (http://blogs.msdn.com/b/efdesign/archive/2011/05/04/spatial-types-in-the-entity-framework.aspx) ra khỏi hộp. – Pawel

+0

vấn đề không phải trong dữ liệu không gian vấn đề mà tôi có nhiều chức năng vô hướng tôi muốn sử dụng –

+0

Gert: tôi theo liên kết đó http://stackoverflow.com/questions/10625955/can-sql-level-functions-be-made- các truy vấn có sẵn cho tới LINQ-to-entity và tôi đã sửa đổi edmx và vấn đề không giải quyết được –

Trả lời

24

Đây là cách bạn làm điều đó:

Bước 1: Trong 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> 

bước 2: Nhập hàm

  1. nhấn đúp chuột vào edmx
  2. Trong giao diện trình duyệt Model, mở rộng GeoDataModel.Store (có thể được đặt tên khác nhau)
  3. mở rộng stored procedures /function
  4. nhấn đúp chuột DistanceBetween
  5. Scalars = Single
  6. Bấm OK

Bước 3: Trong C#:

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

lưu ý rằng IsComposable="false" và không ReturnType và không quên thêm:

 <CommandText> 
     select dbo.DistanceBetween(@lat1,@long1,@lat2,@long2) 
     </CommandText> 

Hy vọng rằng sẽ giúp ....

+0

Điều này dường như hoạt động. Nhưng khi tôi làm mới mô hình (đối với các đối tượng khác), nó đã thay đổi trở lại thành Composable, nó có lỗi. Không biên dịch lỗi, do đó, nó vẫn có thể hoạt động, nhưng dường như không phải là cách tiếp cận dài hạn tốt. Mỗi chức năng đưa ra lỗi trong mô hình. Đoán tạo SPROCs để gọi hàm vẫn là cách tiếp cận của tôi. –

Các vấn đề liên quan