I would also like to add a comment, but to @BenoitGlaizette.
The code polygon.Area.HasValue may cause the following error for some Multipolygons .
ArgumentException: 24144: This operation cannot be completed because the instance is invalid. Use MakeValid to convert an instance to a valid instance. Note that MakeValid can create points of geometry, the instance moves slightly.
However, this will not happen if we directly convert to SqlGeography .
public bool IsInside(DbGeography polygon, double longitude, double latitude) { DbGeography point = DbGeography.FromText(string.Format("POINT({1} {0})", latitude.ToString().Replace(',', '.'), longitude.ToString().Replace(',', '.')), DbGeography.DefaultCoordinateSystemId); var wellKnownText = polygon.AsText(); var sqlGeography = SqlGeography.STGeomFromText(new SqlChars(wellKnownText), DbGeography.DefaultCoordinateSystemId) .MakeValid();
For those using Entity Framework 5 <:
I use this extension method to check all Polygon and Multipolygon before storing them in the database.
public static DbGeography MakePolygonValid(this DbGeography geom) { var wellKnownText = geom.AsText();
Then I can use this method to test Intersects at the database level.
public static class GeoHelper { public const int SridGoogleMaps = 4326; public const int SridCustomMap = 3857; public static DbGeography PointFromLatLng(double lat, double lng) { return DbGeography.PointFromText( "POINT(" + lng.ToString(CultureInfo.InvariantCulture) + " " + lat.ToString(CultureInfo.InvariantCulture) + ")", SridGoogleMaps); } } public County GetCurrentCounty(double latitude, double longitude) { var point = GeoHelper.PointFromLatLng(latitude, longitude); var county = db.Counties.FirstOrDefault(x => x.Area.Intersects(point)); return county; }
T-SQL generated by Entity Framework:
SELECT TOP (1) [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name], [Extent1].[Code] AS [Code], [Extent1].[Area] AS [Area] FROM [Election].[County] AS [Extent1] WHERE ([Extent1].[Area].STIntersects(@p__linq__0)) = 1 -- p__linq__0: 'POINT (10.0000000 32.0000000)' (Type = Object)
You can check this manually:
declare @p__linq__0 varchar(max) set @p__linq__0 = 'POINT (10.0000000 32.0000000)' SELECT TOP (1) [Extent1].[Id] AS [Id], [Extent1].[Name] AS [Name], [Extent1].[Code] AS [Code], [Extent1].[Area] AS [Area] FROM [Election].[County] AS [Extent1] WHERE ([Extent1].[Area].STIntersects(@p__linq__0)) = 1
More detailed information can be found here:
https://docs.microsoft.com/en-us/sql/t-sql/spatial-geometry/stintersects-geometry-data-type