1

我已经实现了与 Nerddinner 中相同的函数“distancebetween”。我创建了一个机场存储库并拥有以下方法:

    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 {“类型'AirTravelMVC3.Models.Repository.AirportRepository'的指定方法'Double DistanceBetween(Double,Double,Double,Double)'无法转换为LINQ to Entities存储表达式,因为没有重载与传递的参数匹配。” } System.SystemException {System.NotSupportedException}

您对为什么会发生这种情况有任何想法吗?我的工作和 nerddinner 的唯一不同是我在实体框架中使用了 POCO 插件。

SQL UDF如下,它在数据库中运行良好:

创建函数 [dbo].[DistanceBetween](@Lat1 真实,
@Long1 真实,@Lat2 真实,@Long2 真实)
返回真实
作为
开始

将@dLat1InRad 声明为 float(53);
SET @dLat1InRad = @Lat1 * (PI()/180.0);
将@dLong1InRad 声明为 float(53);
SET @dLong1InRad = @Long1 * (PI()/180.0);
将@dLat2InRad 声明为 float(53);
SET @dLat2InRad = @Lat2 * (PI()/180.0);
将@dLong2InRad 声明为 float(53);
SET @dLong2InRad = @Long2 * (PI()/180.0);

将@dLongitude 声明为浮点数(53);
SET @dLongitude = @dLong2InRad - @dLong1InRad;
将@dLatitude 声明为浮点数(53);
SET @dLatitude = @dLat2InRad - @dLat1InRad;
/* 中间结果 a. */
将@a 声明为浮点数(53);
SET @a = SQUARE (SIN (@dLatitude / 2.0)) + COS (@dLat1InRad)
* COS (@dLat2InRad)
* SQUARE(SIN (@dLongitude / 2.0));
/* 中间结果 c(以弧度表示的大圆距离)。*/
将@c 声明为真实的;
SET @c = 2.0 * ATN2 (SQRT (@a), SQRT (1.0 - @a));
将@kEarthRadius 声明为真实;
/* SET kEarthRadius = 3956.0 英里 */
设置@kEarthRadius = 6376.5; /* 公里 */

将@dDistance 声明为真实;
设置@dDistance = @kEarthRadius * @c;
返回(@dDistance);
结尾
 
4

3 回答 3

1

为了使用 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>();
}
于 2011-07-07T14:12:25.740 回答
0

假设 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 ,然后调用您的距离来优化结果。

于 2011-06-20T21:11:24.510 回答
0

在对数据库架构进行了几次更改并“从数据库更新模型”后,我得到了同样的异常。

在将我的 EDMX XML 与来自 Nerd Dinner 的原始文件进行比较后,我看到我的已将 DistanceBetween 函数的所有类型更改为“真实”,而 Nerd Dinner 则为“float”。将它们改回浮动解决了这个问题。

于 2013-05-26T03:28:27.593 回答