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

NTS(NetTopologySuite)는 .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
      • 다중 포인트
      • MultiLineString
      • MultiPolygon

Warning

CircularString, CompoundCurve 및 CurePolygon은 NTS에서 지원되지 않습니다.

기본 기하 도형 형식을 사용하면 모든 형식의 셰이프를 속성으로 지정할 수 있습니다.

경도 및 위도

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 패키지는 공간 속성을 사용하여 리버스 엔지니어링 모델도 사용할 수 있지만 Scaffold-DbContext 또는 dotnet ef dbcontext scaffold를 실행하기 전에 패키지를 설치해야 합니다. 그렇지 않으면 열에 대한 형식 매핑을 찾지 못한다는 경고가 표시되고 열은 건너뜁니다.

클라이언트 작업 중에 SRID 무시됨

NTS는 작업 중에 SRID 값을 무시합니다. 평면 좌표계를 가정합니다. 즉, 경도 및 위도 측면에서 좌표를 지정하는 경우 거리, 길이 및 영역과 같은 일부 클라이언트 평가 값은 미터가 아닌 각도로 표시됩니다. 보다 의미 있는 값을 얻으려면 먼저 ProjNet(GeoAPI의 경우)과 같은 라이브러리를 사용하여 좌표를 다른 좌표계에 프로젝션해야 합니다.

참고 항목

ProjNet4GeoAPI라는 이전 패키지가 아닌 최신 ProjNet NuGet 패키지를 사용합니다.

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은 GPS 및 기타 지리적 시스템에 사용되는 표준인 WGS 84를 나타냅니다.

추가 리소스

데이터베이스 관련 정보

공간 데이터 작업에 대한 추가 정보는 공급자의 설명서를 참조하세요.

기타 리소스