次の方法で共有


空間データ

空間データは、物理的な位置とオブジェクトの形状を表します。 多くのデータベースでは、他のデータと共にインデックスを作成してクエリできるように、この種類のデータがサポートされています。 一般的なシナリオとしては、特定の場所から特定の距離内にあるオブジェクトのクエリを実行したり、境界線に特定の場所が含まれているオブジェクトを選択したりします。 EF Core では、NetTopologySuite 空間ライブラリを使用した空間データ型へのマッピングがサポートされています。

インストール

EF Core で空間データを使用するには、適切なサポート NuGet パッケージをインストールする必要があります。 インストールする必要があるパッケージは、使用しているプロバイダーによって異なります。

EF Core プロバイダー Spatial 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 (ラインストリング)
    • 多角形
    • ジオメトリコレクション
      • MultiPoint
      • マルチラインストリング
      • MultiPolygon

Warnung

CircularString、CompoundCurve、および CurePolygon は NTS ではサポートされていません。

基本の 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 = 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 パッケージでは、空間プロパティを持つリバース エンジニアリング モデルも有効になりますが、またはを実行するdotnet ef dbcontext scaffoldパッケージをインストールする必要があります。 そうしないと、列の型マッピングが見つからないという警告が表示され、列はスキップされます。

SRID クライアント操作中は無視されます

NTS は、操作中に SRID 値を無視します。 平面座標系を想定しています。 つまり、経度と緯度の観点から座標を指定した場合、距離、長さ、面積などのクライアントによって評価される値の一部は、メートルではなく度単位になります。 より意味のある値を得るために、まず 、ProjNet (GeoAPI の場合) などのライブラリを使用して、座標を別の座標系に投影する必要があります。

ProjNet4GeoAPI と呼ばれる古いパッケージではなく、新しい ProjNet NuGet パッケージを使用します。

操作が SQL 経由で EF Core によってサーバー評価される場合、結果の単位はデータベースによって決定されます。

ProjNet を使用して 2 つの都市間の距離を計算する例を次に示します。

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 は、GPS やその他の地理システムで使用される標準である WGS 84 を指します。

その他のリソース

データベース固有の情報

空間データの操作に関する追加情報については、プロバイダーのドキュメントをお読みください。

その他のリソース