Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Spatial docs #2723

Merged
merged 1 commit into from
Oct 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
309 changes: 32 additions & 277 deletions entity-framework/core/modeling/spatial.md

Large diffs are not rendered by default.

99 changes: 99 additions & 0 deletions entity-framework/core/providers/sql-server/spatial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
---
title: Microsoft SQL Server Database Provider - Spatial Data - EF Core
description: Using spatial data with the Entity Framework Core Microsoft SQL Server database provider
author: bricelam
ms.author: bricelam
ms.date: 10/02/2020
uid: core/providers/sql-server/spatial
---
# 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](xref:core/modeling/spatial) documentation.

## Geography or geometry

By default, spatial properties are mapped to `geography` columns in SQL Server. To use `geometry`, [configure the column type](xref:core/modeling/entity-properties#column-data-types) in your model.

## Geography polygon rings
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a lower-level heading?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, it's not really related to choosing between geometry or geography


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](https://nettopologysuite.github.io/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](xref:core/modeling/spatial) documentation, NTS currently cannot represent curves. This means that you'll need to transform CircularString, CompoundCurve, and CurePolygon values using the [STCurveToLine](/sql/t-sql/spatial-geography/stcurvetoline-geography-data-type) method before using them in EF Core.

> [!WARNING]
> CircularString, CompoundCurve, and CurePolygon aren't supported by NTS.

## Translated Operations

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

## Additional resources

* [Spatial Data in SQL Server](/sql/relational-databases/spatial/spatial-data-sql-server)
* [NetTopologySuite Docs](https://nettopologysuite.github.io/NetTopologySuite/)
134 changes: 134 additions & 0 deletions entity-framework/core/providers/sqlite/spatial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
---
title: SQLite Database Provider - Spatial Data - EF Core
description: Using spatial data with the Entity Framework Core SQLite database provider
author: bricelam
ms.author: bricelam
ms.date: 10/02/2020
uid: core/providers/sqlite/spatial
---
# Spatial Data in the SQLite EF Core Provider

This page includes additional information about using spatial data with the SQLite database provider. For general information about using spatial data in EF Core, see the main [Spatial Data](xref:core/modeling/spatial) documentation.

## Installing SpatiaLite

On Windows, the native mod_spatialite library is distributed as a NuGet package dependency. Other platforms need to install it separately. This is typically done using a software package manager. For example, you can use APT on Debian and Ubuntu; and Homebrew on MacOS.

``` sh
# Debian/Ubuntu
apt-get install libsqlite3-mod-spatialite

# macOS
brew install libspatialite
```

Unfortunately, newer versions of PROJ (a dependency of SpatiaLite) are incompatible with EF's default [SQLitePCLRaw bundle](/dotnet/standard/data/sqlite/custom-versions#bundles). You can work around this by using the system SQLite library instead.

```xml
<ItemGroup>
<!-- Use bundle_sqlite3 instead with SpatiaLite on macOS and Linux -->
<!--<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="3.1.0" />-->
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="3.1.0" />
<PackageReference Include="SQLitePCLRaw.bundle_sqlite3" Version="2.0.4" />

<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.NetTopologySuite" Version="3.1.0" />
</ItemGroup>
```

On **macOS**, you'll also need set an environment variable before running your app so it uses Homebrew's version of SQLite. In Visual Studio for Mac, you can set this under **Project > Project Options > Run > Configurations > Default**

```sh
DYLD_LIBRARY_PATH=/usr/local/opt/sqlite/lib
```

## Configuring SRID

In SpatiaLite, columns need to specify an SRID per column. The default SRID is `0`. Specify a different SRID using the ForSqliteHasSrid method.

``` csharp
modelBuilder.Entity<City>().Property(c => c.Location)
.ForSqliteHasSrid(4326);
```

> [!NOTE]
> 4326 refers to WGS 84, a standard used in GPS and other geographic systems.

## Dimension

The default dimension (or ordinates) of a column is X and Y. To enable additional ordinates like Z or M, configure the column type.

``` csharp
modelBuilder.Entity<City>().Property(c => c.Location)
.HasColumnType("POINTZ");
```

## Translated Operations

This table shows which [NetTopologySuite](https://nettopologysuite.github.io/NetTopologySuite/) (NTS) members are translated into which SQL functions.

.NET | SQL
------------------------------------------- | ---
geometry.Area | Area(@geometry)
geometry.AsBinary() | AsBinary(@geometry)
geometry.AsText() | AsText(@geometry)
geometry.Boundary | Boundary(@geometry)
geometry.Buffer(distance) | Buffer(@geometry, @distance)
geometry.Buffer(distance, quadrantSegments) | Buffer(@geometry, @distance, @quadrantSegments)
geometry.Centroid | Centroid(@geometry)
geometry.Contains(g) | Contains(@geometry, @g)
geometry.ConvexHull() | ConvexHull(@geometry)
geometry.CoveredBy(g) | CoveredBy(@geometry, @g)
geometry.Covers(g) | Covers(@geometry, @g)
geometry.Crosses(g) | Crosses(@geometry, @g)
geometry.Difference(other) | Difference(@geometry, @other)
geometry.Dimension | Dimension(@geometry)
geometry.Disjoint(g) | Disjoint(@geometry, @g)
geometry.Distance(g) | Distance(@geometry, @g)
geometry.Envelope | Envelope(@geometry)
geometry.EqualsTopologically(g) | Equals(@geometry, @g)
geometry.GeometryType | GeometryType(@geometry)
geometry.GetGeometryN(n) | GeometryN(@geometry, @n + 1)
geometry.InteriorPoint | PointOnSurface(@geometry)
geometry.Intersection(other) | Intersection(@geometry, @other)
geometry.Intersects(g) | Intersects(@geometry, @g)
geometry.IsEmpty | IsEmpty(@geometry)
geometry.IsSimple | IsSimple(@geometry)
geometry.IsValid | IsValid(@geometry)
geometry.IsWithinDistance(geom, distance) | Distance(@geometry, @geom) <= @distance
geometry.Length | GLength(@geometry)
geometry.NumGeometries | NumGeometries(@geometry)
geometry.NumPoints | NumPoints(@geometry)
geometry.OgcGeometryType | CASE GeometryType(@geometry) WHEN 'POINT' THEN 1 ... END
geometry.Overlaps(g) | Overlaps(@geometry, @g)
geometry.PointOnSurface | PointOnSurface(@geometry)
geometry.Relate(g, intersectionPattern) | Relate(@geometry, @g, @intersectionPattern)
geometry.Reverse() | ST_Reverse(@geometry)
geometry.SRID | SRID(@geometry)
geometry.SymmetricDifference(other) | SymDifference(@geometry, @other)
geometry.ToBinary() | AsBinary(@geometry)
geometry.ToText() | AsText(@geometry)
geometry.Touches(g) | Touches(@geometry, @g)
geometry.Union() | UnaryUnion(@geometry)
geometry.Union(other) | GUnion(@geometry, @other)
geometry.Within(g) | Within(@geometry, @g)
geometryCollection[i] | GeometryN(@geometryCollection, @i + 1)
geometryCollection.Count | NumGeometries(@geometryCollection)
lineString.Count | NumPoints(@lineString)
lineString.EndPoint | EndPoint(@lineString)
lineString.GetPointN(n) | PointN(@lineString, @n + 1)
lineString.IsClosed | IsClosed(@lineString)
lineString.IsRing | IsRing(@lineString)
lineString.StartPoint | StartPoint(@lineString)
multiLineString.IsClosed | IsClosed(@multiLineString)
point.M | M(@point)
point.X | X(@point)
point.Y | Y(@point)
point.Z | Z(@point)
polygon.ExteriorRing | ExteriorRing(@polygon)
polygon.GetInteriorRingN(n) | InteriorRingN(@polygon, @n + 1)
polygon.NumInteriorRings | NumInteriorRing(@polygon)

## Additional resources

* [SpatiaLite Homepage](https://www.gaia-gis.it/fossil/libspatialite)
* [NetTopologySuite Docs](https://nettopologysuite.github.io/NetTopologySuite/)
6 changes: 6 additions & 0 deletions entity-framework/toc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@
href: core/providers/sql-server/indexes.md
- name: Memory-optimized tables
href: core/providers/sql-server/memory-optimized-tables.md
- name: Spatial data
displayName: GIS
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we leave spatial data as the display name? Am just not sure everyone knows the name GIS. Not sure.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add Spatial Data too for localization.

Copy link
Contributor Author

@bricelam bricelam Oct 2, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lol, displayName has nothing to do with the displayed name. (But I can certainly see why you might think that.) It's for additional keywords users can search for:
image

href: core/providers/sql-server/spatial.md
- name: Specify Azure SQL Database options
href: core/providers/sql-server/azure-sql-database.md
- name: SQLite
Expand All @@ -241,6 +244,9 @@
href: core/providers/sqlite/index.md
- name: SQLite limitations
href: core/providers/sqlite/limitations.md
- name: Spatial data
displayName: GIS
href: core/providers/sqlite/spatial.md
- name: Cosmos
items:
- name: Overview
Expand Down
Loading