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?