Question

I know for a fact that my database contains a post with these two properties:

latitude:  44.611589
longitude: -122.215347

I am writing a method to find all posts in the database that are within 50.0 meters of that location. (So, in this case, since there is a post with these exact coordinates, it will have a distance of 0 meters and should be included).

Here's my code:

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.

Why is my collection empty? The LINQ query, when executed, should look exactly like the code for double d because p.Longitude and p.Latitude will be equal to their respective values (which definitely exist in the database, I hard coded them in there).

EDIT:

When I hard-code the values in the query it works:

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

This returns properly the post that has the correct lat/long values. So I think its fair to assume that SqlFunctions.StringConvert() doesn't work, but I have no way to test that because it doesn't seem to work outside of a LINQ expression. Also, String.format and double.toString() don't work inside LINQ expressions.

Confirmed, its a problem with 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);

This also doesn't work (returns empty collection).

EDIT: Here's the SQL that my LINQ query generates:

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))

That SQL doesn't work, and its the STR(cast(...)) part that doesn't work. When I replace this with this it does work:

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)

So technically I can write my own SQL. Yay. Now is there any way to do this through LINQ to Entities?

Was it helpful?

Solution

Try PointFromText instead of 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);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top