使用DbGeography距离和实体框架时的空响应

时间:2013-12-22 08:42:07

标签: sql-server linq entity-framework linq-to-entities latitude-longitude

我知道我的数据库包含一个包含这两个属性的帖子:

latitude:  44.611589
longitude: -122.215347

我正在编写一种方法来查找数据库中距离该位置50.0米范围内的所有帖子。 (因此,在这种情况下,由于有一个具有这些精确坐标的帖子,它的距离为0米,应该包括在内。)

这是我的代码:

DbGeography queryLocation = DbGeography.FromText("POINT(-122.215437 44.611589)", 4326);

double d = (double) DbGeography.FromText(
            "POINT(-122.215347 44.611589)"
            , 4326)
            .Distance(queryLocation);

//d is equal to 0 when I execute this, as expected.

IQueryable<Post> posts = db.Posts.Where(p => (double) DbGeography.FromText(
            "POINT(" + SqlFunctions.StringConvert(p.Longitude) + " " + SqlFunctions.StringConvert(p.Latitude) + ")"
            , 4326).Distance(queryLocation) <= 50.0);

//posts is an empty collection when this executes.

为什么我的收藏是空的? LINQ查询在执行时应该看起来与double d的代码完全相同,因为p.Longitudep.Latitude将等于它们各自的值(它们肯定存在于数据库中,我对它们进行了硬编码在那里)。

编辑:

当我对查询中的值进行硬编码时,它可以工作:

var posts = db.Posts
            .Where(p => (double) DbGeography.FromText(
            "POINT(-122.215347 47.611589)"
            , Constants.MetersCoordinateSystemId)
            .Distance(queryLocation) <= 50.0);

这会正确返回具有正确纬度/经度值的帖子。所以我认为可以假设SqlFunctions.StringConvert()不起作用,但我无法测试它,因为它似乎不能在LINQ表达式之外工作。此外,String.format和double.toString()在LINQ表达式中不起作用。

确认,它是SqlFunctions.StringConvert()

的问题
var posts = db.Posts
            .Where(p => (double) DbGeography.FromText(
            "POINT(" + SqlFunctions.StringConvert(-122.215347) + " " + SqlFunctions.StringConvert(47.611589) + ")"
            , Constants.MetersCoordinateSystemId)
            .Distance(queryLocation) <= 50.0);

这也不起作用(返回空集合)。

编辑:这是我的LINQ查询生成的SQL:

SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[UserId] AS [UserId], 
    [Extent1].[Latitude] AS [Latitude], 
    [Extent1].[Longitude] AS [Longitude]
    FROM [dbo].[Posts] AS [Extent1]
    WHERE (geography::STGeomFromText(N'POINT(' + STR(cast(-122.215347 as float(53))) + N' ' + STR(cast(44.611589 as float(53))) + N')', 4326).STDistance(@p__linq__0)) <= cast(50 as float(53))

SQL不起作用,而STR(cast(...))部分不起作用。当我用它替换它时它确实有用:

SELECT 
    [Extent1].[Id] AS [Id], 
    [Extent1].[UserId] AS [UserId], 
    [Extent1].[Latitude] AS [Latitude], 
    [Extent1].[Longitude] AS [Longitude]
    FROM [dbo].[Posts] AS [Extent1]
    WHERE (geography::STGeomFromText(N'POINT(' + LTRIM(Str(-122.215347, 25, 5)) 
+ N' ' + LTRIM(Str(44.611589, 25, 5)) + N')', 4326).STDistance(geography::STGeomFromText(N'POINT(-122.215347 47.611589)',4326)) <= 50)

从技术上讲,我可以编写自己的SQL。好极了。现在有没有办法通过LINQ to Entities做到这一点?

1 个答案:

答案 0 :(得分:0)

尝试使用PointFromText而不是FromText:

DbGeography queryLocation = DbGeography.PointFromText("POINT(-122.215437 44.611589)", 4326);

double d = (double) DbGeography.PointFromText(
            "POINT(-122.215347 44.611589)"
            , 4326)
            .Distance(queryLocation);

//d is equal to 0 when I execute this, as expected.

IQueryable<Post> posts = db.Posts.Where(p => (double) DbGeography.PointFromText(
            "POINT(" + SqlFunctions.StringConvert(p.Longitude) + " " + SqlFunctions.StringConvert(p.Latitude) + ")"
            , 4326).Distance(queryLocation) <= 50.0);