实体框架中的数据库函数无法返回结果

时间:2011-06-20 20:22:23

标签: asp.net sql entity-framework nerddinner

我已经实现了与Nerddinner相同的“distance between”功能。我创建了一个机场存储库并使用这些方法:

    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如下所示,它在数据库中运行良好:

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 个答案:

答案 0 :(得分:1)

为了使用现有NerdDinner源的POCO执行此操作,我必须将其添加到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>();
}

答案 1 :(得分: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那个,然后调用你的距离来细化结果。

答案 2 :(得分:0)

在对数据库模式进行了一些更改并“从数据库更新了模型”之后,我遇到了同样的异常。

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