Share via


空間資料

空間資料代表物件的實體位置和形狀。 許多資料庫都支援這種類型的資料,以便與其他資料一起編制索引和查詢。 常見案例包括查詢指定距離某個位置內的物件,或選取框線包含指定位置的物件。 EF Core 支援使用 NetTopologySuite 空間程式庫對應至空間資料類型。

正在安裝

若要搭配 EF Core 使用空間資料,您必須安裝適當的支援 NuGet 套件。 您需要安裝的套件取決於您所使用的提供者。

EF Core 提供者 空間 NuGet 套件
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

NetTopologySuite

NetTopologySuite (NTS) 是適用于 .NET 的空間程式庫。 EF Core 可讓您使用模型中的 NTS 類型,對應至資料庫中的空間資料類型。

若要透過 NTS 啟用空間類型的對應,請在提供者的 DbCoNtext 選項產生器上呼叫 UseNetTopologySuite 方法。 例如,使用 SQL Server 時,您會呼叫它,如下所示。

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

有數種空間資料類型。 您使用的類型取決於您想要允許的圖形類型。 以下是可用於模型中屬性之 NTS 類型的階層。 它們位於 命名空間內 NetTopologySuite.Geometries

  • 幾何
    • Point
    • LineString
    • Polygon
    • GeometryCollection
      • MultiPoint
      • MultiLineString
      • MultiPolygon

警告

NTS 不支援 CircularString、CompoundCurve 和 CurePolygon。

使用基底 Geometry 類型可讓 屬性指定任何類型的圖形。

經度和緯度

NTS 中的座標以 X 和 Y 值表示。 若要代表經度和緯度,請將 X 用於經度,並使用 Y 表示緯度。 請注意,這會 latitude, longitude 您通常看到這些值的格式回溯

查詢資料

下列實體類別可用來對應至 Wide World Importers 範例資料庫中 資料表。

[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; }
}

在 LINQ 中,作為資料庫函式可用的 NTS 方法和屬性將會轉譯為 SQL。 例如,Distance 和 Contains 方法會在下列查詢中轉譯。 請參閱提供者的檔,以瞭解支援哪些方法。

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

反向工程

空間 NuGet 套件也啟用 具有空間屬性的反向工程 模型,但您需要在執行 或 dotnet ef dbcontext scaffold 之前 Scaffold-DbContext 先安裝套件。 如果您未這麼做,您將會收到有關未尋找資料行類型對應,且將會略過資料行的警告。

在用戶端作業期間忽略 SRID

NTS 會在作業期間忽略 SRID 值。 它會假設平面座標系統。 這表示,如果您在經度和緯度方面指定座標,某些用戶端評估的值,例如距離、長度和區域會以度為單位,而不是公尺。 如需更有意義的值,您必須先使用 ProjNet 等 程式庫將座標投影到另一個座標系統(適用于 GeoAPI)。

注意

使用較 新的 ProjNet NuGet 套件 而不是 稱為 ProjNet4GeoAPI 的較舊套件。

如果透過 SQL 由 EF Core 評估作業,結果的單位將由資料庫決定。

以下是使用 ProjNet 來計算兩個城市之間的距離的範例。

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

注意

4326 是指 WGS 84,這是 GPS 和其他地理系統中使用的標準。

其他資源

資料庫特定資訊

請務必閱讀提供者的檔,以取得使用空間資料的其他資訊。

其他資源