Функции базы данных в Entity Framework не могут возвращать результаты - PullRequest
1 голос
/ 21 июня 2011

Я реализовал ту же функцию "distancebetween", что и в Nerddinner. Я создал хранилище в аэропорту, и у меня есть следующие методы:

    public IQueryable<AllAirports> ReturnAllAirportWithIn50milesOfAPoint(double lat, double lon)
    {
        var airports = from d in im.AllAirports
               where DistanceBetween(lat, lon, (double)d.Lat, (double)d.Lon) < 1000.00
               select d;
        return airports;
    }

    [EdmFunction("AirTravelModel.Store", "DistanceBetween")]
    public static double DistanceBetween(double lat1, double long1, double lat2, double long2)
    {
        throw new NotImplementedException("Only call through LINQ expression");
    }

Когда я проверял это, он показывает:

base {"Указанный метод 'Double DistanceBetween (Double, Double, Double, Double)' для типа 'AirTravelMVC3.Models.Repository.AirportRepository' не может быть переведен в LINQ to Entities сохранить выражение, поскольку перегрузка не соответствует переданным аргументам. "} System.SystemException {System.NotSupportedException}

У вас есть идеи, почему это происходит? Единственное различие между моей работой и nerddinner состоит в том, что я использовал плагин POCO в платформе сущностей.

UDF SQL выглядит следующим образом, он очень хорошо работает в базе данных:

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 * (PI()/180.0);
DECLARE @dLong1InRad as float(53);
SET @dLong1InRad = @Long1 * (PI()/180.0);
DECLARE @dLat2InRad as float(53);
SET @dLat2InRad = @Lat2 * (PI()/180.0);
DECLARE @dLong2InRad as float(53);
SET @dLong2InRad = @Long2 * (PI()/180.0);

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
 

Ответы [ 3 ]

1 голос
/ 07 июля 2011

Чтобы сделать это, используя POCO с существующим источником NerdDinner, мне пришлось добавить это в класс DinnerRepository:

public IQueryable<Dinner> FindByLocation(float latitude, float longitude)
{
    List<Dinner> resultList = new List<Dinner>();

    var results = db.Database.SqlQuery<Dinner>("SELECT * FROM Dinners WHERE EventDate >= {0} AND dbo.DistanceBetween({1}, {2}, Latitude, Longitude) < 1000", DateTime.Now, latitude, longitude);
    foreach (Dinner result in results)
    {
        resultList.Add(db.Dinners.Where(d => d.DinnerID == result.DinnerID).FirstOrDefault());
    }

    return resultList.AsQueryable<Dinner>();
}
0 голосов
/ 26 мая 2013

Я получил это же исключение после того, как внес несколько изменений в схему БД и "обновил модель из базы данных".

После сравнения моего EDMX XML с оригиналом из Nerd Dinner я обнаружил, что мой изменил все типы для функции DistanceBetween на «real», где Nerd Dinner имел «float».Изменение их обратно на float решило проблему.

0 голосов
/ 21 июня 2011

Предполагая, что DistanceBetween реализован в c # Проблема (на что намекал @ p.campbell) заключается в том, что генератор запросов не знает, как вычислять DistanceBetween

Чтобы ваш код работал как есть, вам может понадобиться что-то вроде

public IQueryable<AllAirports> ReturnAllAirportWithIn50milesOfAPoint(double lat, double lon)
{
    var airports = from d in im.AllAirports.ToList()
           where DistanceBetween(lat, lon, (double)d.Lat, (double)d.Lon) < 1000.00
           select d;
    return airports;
}

ToList () заставит AllAirports выполнить оценку в виде списка, затем его можно будет оценить в памяти, используя вашу функцию c #. Очевидно, что это не масштабируется до огромного количества аэропортов. Если это было проблемой, вы можете выполнить грубый «рамочный» запрос, где вы просто делаете дешевое выражение в квадрате, чтобы вернуть небольшое количество аэропортов, ToList, а затем вызываете расстояние между ними, чтобы уточнить результаты.

...