共用方式為


空間數據

空間數據代表對象的實體位置和形狀。 許多資料庫都支援這種類型的數據,以便與其他數據一起編製索引和查詢。 常見案例包括查詢指定距離某個位置內的物件,或選取框線包含指定位置的物件。 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
FileBaseContext 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

  • 幾何學
    • LineString(線串)
    • 多邊形
    • GeometryCollection
      • MultiPoint
      • 多行字符串
      • MultiPolygon

警告

NTS 不支援 CircularString、CompoundCurve 和 CurePolygon。

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

經度和緯度

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

查詢資料

下列實體類別可以映射到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 = 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));

反向工程

空間 NuGet 套件也啟用具有空間屬性的反向工程模型,但您需要在執行 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 和其他地理系統中使用的標準。

其他資源

資料庫特定資訊

請務必閱讀您的提供者文件,以取得更多關於使用空間資料的資訊。

其他資源