Spatial Data in the SQL Server EF Core Provider

This page includes additional information about using spatial data with the Microsoft SQL Server database provider. For general information about using spatial data in EF Core, see the main Spatial Data documentation.

Geography or geometry

By default, spatial properties are mapped to geography columns in SQL Server. To use geometry, configure the column type in your model.

Geography polygon rings

When using the geography column type, SQL Server imposes additional requirements on the exterior ring (or shell) and interior rings (or holes). The exterior ring must be oriented counterclockwise and the interior rings clockwise. NetTopologySuite (NTS) validates this before sending values to the database.

FullGlobe

SQL Server has a non-standard geometry type to represent the full globe when using the geography column type. It also has a way to represent polygons based on the full globe (without an exterior ring). Neither of these are supported by NTS.

Warning

FullGlobe and polygons based on it aren't supported by NTS.

Curves

As mentioned in the main Spatial Data documentation, NTS currently cannot represent curves. This means that you'll need to transform CircularString, CompoundCurve, and CurePolygon values using the STCurveToLine method before using them in EF Core.

Warning

CircularString, CompoundCurve, and CurePolygon aren't supported by NTS.

Spatial function mappings

This table shows which NTS members are translated into which SQL functions. Note that the translations vary depending on whether the column is of type geography or geometry.

.NET SQL (geography) SQL (geometry) Added in
EF.Functions.CurveToLine(geometry) @geometry.STCurveToLine() @geometry.STCurveToLine() EF Core 7.0
geometry.Area @geometry.STArea() @geometry.STArea()
geometry.AsBinary() @geometry.STAsBinary() @geometry.STAsBinary()
geometry.AsText() @geometry.AsTextZM() @geometry.AsTextZM()
geometry.Boundary @geometry.STBoundary()
geometry.Buffer(distance) @geometry.STBuffer(@distance) @geometry.STBuffer(@distance)
geometry.Centroid @geometry.STCentroid()
geometry.Contains(g) @geometry.STContains(@g) @geometry.STContains(@g)
geometry.ConvexHull() @geometry.STConvexHull() @geometry.STConvexHull()
geometry.Crosses(g) @geometry.STCrosses(@g)
geometry.Difference(other) @geometry.STDifference(@other) @geometry.STDifference(@other)
geometry.Dimension @geometry.STDimension() @geometry.STDimension()
geometry.Disjoint(g) @geometry.STDisjoint(@g) @geometry.STDisjoint(@g)
geometry.Distance(g) @geometry.STDistance(@g) @geometry.STDistance(@g)
geometry.Envelope @geometry.STEnvelope()
geometry.EqualsTopologically(g) @geometry.STEquals(@g) @geometry.STEquals(@g)
geometry.GeometryType @geometry.STGeometryType() @geometry.STGeometryType()
geometry.GetGeometryN(n) @geometry.STGeometryN(@n + 1) @geometry.STGeometryN(@n + 1)
geometry.InteriorPoint @geometry.STPointOnSurface()
geometry.Intersection(other) @geometry.STIntersection(@other) @geometry.STIntersection(@other)
geometry.Intersects(g) @geometry.STIntersects(@g) @geometry.STIntersects(@g)
geometry.IsEmpty @geometry.STIsEmpty() @geometry.STIsEmpty()
geometry.IsSimple @geometry.STIsSimple()
geometry.IsValid @geometry.STIsValid() @geometry.STIsValid()
geometry.IsWithinDistance(geom, distance) @geometry.STDistance(@geom) <= @distance @geometry.STDistance(@geom) <= @distance
geometry.Length @geometry.STLength() @geometry.STLength()
geometry.NumGeometries @geometry.STNumGeometries() @geometry.STNumGeometries()
geometry.NumPoints @geometry.STNumPoints() @geometry.STNumPoints()
geometry.OgcGeometryType CASE @geometry.STGeometryType() WHEN N'Point' THEN 1 ... END CASE @geometry.STGeometryType() WHEN N'Point' THEN 1 ... END
geometry.Overlaps(g) @geometry.STOverlaps(@g) @geometry.STOverlaps(@g)
geometry.PointOnSurface @geometry.STPointOnSurface()
geometry.Relate(g, intersectionPattern) @geometry.STRelate(@g, @intersectionPattern)
geometry.SRID @geometry.STSrid @geometry.STSrid
geometry.SymmetricDifference(other) @geometry.STSymDifference(@other) @geometry.STSymDifference(@other)
geometry.ToBinary() @geometry.STAsBinary() @geometry.STAsBinary()
geometry.ToText() @geometry.AsTextZM() @geometry.AsTextZM()
geometry.Touches(g) @geometry.STTouches(@g)
geometry.Union(other) @geometry.STUnion(@other) @geometry.STUnion(@other)
geometry.Within(g) @geometry.STWithin(@g) @geometry.STWithin(@g)
geometryCollection[i] @geometryCollection.STGeometryN(@i + 1) @geometryCollection.STGeometryN(@i + 1)
geometryCollection.Count @geometryCollection.STNumGeometries() @geometryCollection.STNumGeometries()
lineString.Count @lineString.STNumPoints() @lineString.STNumPoints()
lineString.EndPoint @lineString.STEndPoint() @lineString.STEndPoint()
lineString.GetPointN(n) @lineString.STPointN(@n + 1) @lineString.STPointN(@n + 1)
lineString.IsClosed @lineString.STIsClosed() @lineString.STIsClosed()
lineString.IsRing @lineString.IsRing()
lineString.StartPoint @lineString.STStartPoint() @lineString.STStartPoint()
multiLineString.IsClosed @multiLineString.STIsClosed() @multiLineString.STIsClosed()
point.M @point.M @point.M
point.X @point.Long @point.STX
point.Y @point.Lat @point.STY
point.Z @point.Z @point.Z
polygon.ExteriorRing @polygon.RingN(1) @polygon.STExteriorRing()
polygon.GetInteriorRingN(n) @polygon.RingN(@n + 2) @polygon.STInteriorRingN(@n + 1)
polygon.NumInteriorRings @polygon.NumRings() - 1 @polygon.STNumInteriorRing()

Aggregate functions

.NET SQL Added in
GeometryCombiner.Combine(group.Select(x => x.Property)) CollectionAggregate(Property) EF Core 7.0
ConvexHull.Create(group.Select(x => x.Property)) ConvexHullAggregate(Property) EF Core 7.0
UnaryUnionOp.Union(group.Select(x => x.Property)) UnionAggregate(Property) EF Core 7.0
EnvelopeCombiner.CombineAsGeometry(group.Select(x => x.Property)) EnvelopeAggregate(Property) EF Core 7.0

Additional resources