Dela via


Spatiala data

Rumsliga data representerar den fysiska platsen och objektens form. Många databaser har stöd för den här typen av data så att de kan indexeras och efterfrågas tillsammans med andra data. Vanliga scenarier är att fråga efter objekt inom ett visst avstånd från en plats eller välja objektet vars kantlinje innehåller en viss plats. EF Core stöder mappning till rumsliga datatyper med hjälp av det rumsliga biblioteket NetTopologySuite.

Installera

För att använda rumsliga data med EF Core måste du installera det lämpliga NuGet-paketet. Vilket paket du behöver installera beror på vilken leverantör du använder.

EF Core-provider Spatial NuGet-paket
Microsoft.EntityFrameworkCore.SqlServer Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite
Microsoft.EntityFrameworkCore.Sqlite Microsoft.EntityFrameworkCore.Sqlite.NetTopologySuite
Microsoft.EntityFrameworkCore.InMemory NetTopologySuite
Npgsql.EntityFrameworkCore.PostgreSQL Npgsql.EntityFrameworkCore.PostgreSQL.NetTopologySuite
Pomelo.EntityFrameworkCore.MySql Pomelo.EntityFrameworkCore.MySql.NetTopologySuite
Devart.Data.MySql.EFCore Devart.Data.MySql.EFCore.NetTopologySuite
Devart.Data.Oracle.EFCore Devart.Data.Oracle.EFCore.NetTopologySuite
Devart.Data.PostgreSql.EFCore Devart.Data.PostgreSql.EFCore.NetTopologySuite
Devart.Data.SQLite.EFCore Devart.Data.SQLite.EFCore.NetTopologySuite
Teradata.EntityFrameworkCore Teradata.EntityFrameworkCore.NetTopologySuite
FilBasKontekst NetTopologySuite

NetTopologySuite

NetTopologySuite (NTS) är ett rumsligt bibliotek för .NET. EF Core möjliggör mappning till rumsliga datatyper i databasen med hjälp av NTS-typer i din modell.

Om du vill aktivera mappning till rumsliga typer via NTS anropar du metoden UseNetTopologySuite på providerns DbContext-alternativbyggare. Med SQL Server skulle du till exempel kalla det så här.

options.UseSqlServer(
    @"Data Source=(localdb)\MSSQLLocalDB;Initial Catalog=WideWorldImporters;ConnectRetryCount=0",
    x => x.UseNetTopologySuite());

Det finns flera rumsliga datatyper. Vilken typ du använder beror på vilka typer av former du vill tillåta. Här är hierarkin med NTS-typer som du kan använda för egenskaper i din modell. De finns i NetTopologySuite.Geometries namnområdet.

  • Geometri
    • Punkt
    • LineString
    • Polygon
    • Geometrisamling
      • MultiPoint
      • FlerradSträng
      • MultiPolygon

Varning

CircularString, CompoundCurve och CurePolygon stöds inte av NTS.

Med basgeometritypen kan alla typer av former anges av egenskapen.

Longitud och latitud

Koordinaterna i NTS är i termer av X- och Y-värden. Om du vill representera longitud och latitud använder du X för longitud och Y för latitud. Observera att detta är bakåt från det latitude, longitude format där du vanligtvis ser dessa värden.

Köra frågor mot data

Följande entitetsklasser kan användas för att mappa till tabeller i wide world importers-exempeldatabasen.

[Table("Cities", Schema = "Application")]
public class City
{
    public int CityID { get; set; }

    public string CityName { get; set; }

    public Point Location { get; set; }
}
[Table("Countries", Schema = "Application")]
public class Country
{
    public int CountryID { get; set; }

    public string CountryName { get; set; }

    // Database includes both Polygon and MultiPolygon values
    public Geometry Border { get; set; }
}

I LINQ översätts de NTS-metoder och egenskaper som är tillgängliga som databasfunktioner till SQL. Metoderna Distance och Contains översätts till exempel i följande frågor. Se leverantörens dokumentation för vilka metoder som stöds.

// Find the nearest city
var nearestCity = await db.Cities
    .OrderBy(c => c.Location.Distance(currentLocation))
    .FirstOrDefaultAsync();
// Find the containing country
var currentCountry = await db.Countries
    .FirstOrDefaultAsync(c => c.Border.Contains(currentLocation));

Bakåtkompilering

De rumsliga NuGet-paketen möjliggör även omvända teknikmodeller med rumsliga egenskaper, men du måste installera paketet innan du kör Scaffold-DbContext eller dotnet ef dbcontext scaffold. Om du inte gör det, får du varningar om att typmappningar för kolumnerna inte hittas, och kolumnerna kommer att hoppas över.

SRID ignoreras under klientåtgärder

NTS ignorerar SRID-värden under åtgärder. Det förutsätter ett planarkoordinatsystem. Det innebär att om du anger koordinater i termer av longitud och latitud, kommer vissa klientvärderade värden som avstånd, längd och område att vara i grader, inte meter. För mer meningsfulla värden måste du först projicera koordinaterna till ett annat koordinatsystem med hjälp av ett bibliotek som ProjNet (för GeoAPI).

Anmärkning

Använd det nyare ProjNet NuGet-paketet, inte det äldre paketet projNet4GeoAPI.

Om en åtgärd utvärderas av EF Core via SQL bestäms resultatets enhet av databasen.

Här är ett exempel på hur du använder ProjNet för att beräkna avståndet mellan två städer.

public static class GeometryExtensions
{
    private static readonly CoordinateSystemServices _coordinateSystemServices
        = new CoordinateSystemServices(
            new Dictionary<int, string>
            {
                // Coordinate systems:

                [4326] = GeographicCoordinateSystem.WGS84.WKT,

                // This coordinate system covers the area of our data.
                // Different data requires a different coordinate system.
                [2855] =
                    @"
                        PROJCS[""NAD83(HARN) / Washington North"",
                            GEOGCS[""NAD83(HARN)"",
                                DATUM[""NAD83_High_Accuracy_Regional_Network"",
                                    SPHEROID[""GRS 1980"",6378137,298.257222101,
                                        AUTHORITY[""EPSG"",""7019""]],
                                    AUTHORITY[""EPSG"",""6152""]],
                                PRIMEM[""Greenwich"",0,
                                    AUTHORITY[""EPSG"",""8901""]],
                                UNIT[""degree"",0.01745329251994328,
                                    AUTHORITY[""EPSG"",""9122""]],
                                AUTHORITY[""EPSG"",""4152""]],
                            PROJECTION[""Lambert_Conformal_Conic_2SP""],
                            PARAMETER[""standard_parallel_1"",48.73333333333333],
                            PARAMETER[""standard_parallel_2"",47.5],
                            PARAMETER[""latitude_of_origin"",47],
                            PARAMETER[""central_meridian"",-120.8333333333333],
                            PARAMETER[""false_easting"",500000],
                            PARAMETER[""false_northing"",0],
                            UNIT[""metre"",1,
                                AUTHORITY[""EPSG"",""9001""]],
                            AUTHORITY[""EPSG"",""2855""]]
                    "
            });

    public static Geometry ProjectTo(this Geometry geometry, int srid)
    {
        var transformation = _coordinateSystemServices.CreateTransformation(geometry.SRID, srid);

        var result = geometry.Copy();
        result.Apply(new MathTransformFilter(transformation.MathTransform));

        return result;
    }

    private class MathTransformFilter : ICoordinateSequenceFilter
    {
        private readonly MathTransform _transform;

        public MathTransformFilter(MathTransform transform)
            => _transform = transform;

        public bool Done => false;
        public bool GeometryChanged => true;

        public void Filter(CoordinateSequence seq, int i)
        {
            var x = seq.GetX(i);
            var y = seq.GetY(i);
            var z = seq.GetZ(i);
            _transform.Transform(ref x, ref y, ref z);
            seq.SetX(i, x);
            seq.SetY(i, y);
            seq.SetZ(i, z);
        }
    }
}
var seattle = new Point(-122.333056, 47.609722) { SRID = 4326 };
var redmond = new Point(-122.123889, 47.669444) { SRID = 4326 };

// In order to get the distance in meters, we need to project to an appropriate
// coordinate system. In this case, we're using SRID 2855 since it covers the
// geographic area of our data
var distanceInDegrees = seattle.Distance(redmond);
var distanceInMeters = seattle.ProjectTo(2855).Distance(redmond.ProjectTo(2855));

Anmärkning

4326 avser WGS 84, en standard som används i GPS och andra geografiska system.

Ytterligare resurser

Databasspecifik information

Läs leverantörens dokumentation för ytterligare information om hur du arbetar med rumsliga data.

Andra resurser