deezus blog

.Net Core、Typescriptを中心に技術的ノウハウを公開しています

EntityFrameworkCoreでSQLServerの空間情報を扱う方法

はじめに

SQLServerでGeography型のカラムを扱う方法です

必要なパッケージ

Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite

テーブル構造

例として店舗の座標を保存するだけのテーブルとします

create table stores
(
    id       int identity
        constraint stores_pk
            primary key nonclustered,
    location geography not null
)

DbContext関連

Store.cs

using System.ComponentModel.DataAnnotations.Schema;
using NetTopologySuite.Geometries;

namespace GeoTest
{
    public class Store
    {
        [Column("id")]
        public int Id { get; set; }
        
        [Column("location")]
        public Point Location { get; set; }
    }
}

※この例ではLocationに座標が入る前提のため型をPointにしていますが、PointだけではなくPolygonなどが混在する可能性がある場合は型をIGeometryにします

Db.cs

using Microsoft.EntityFrameworkCore;

namespace GeoTest
{
    public class Db : DbContext
    {
        public DbSet<Store> Stores { get; set; }

        public Db(DbContextOptions options) : base(options)
        {

        }
    }
}

Startup.csの変更

ConfigureServicesに下記を追加します
※接続文字列は適宜変更してください

services.AddDbContext<Db>(op => { 
    op.UseSqlServer([接続文字列], x => x.UseNetTopologySuite()); 
});

使い方

コントローラーにDbがインジェクションされます

using Microsoft.AspNetCore.Mvc;
using NetTopologySuite.Geometries;

namespace GeoTest.Controllers
{
    public class HomeController : Controller
    {
        private Db _db;
        public HomeController(Db db)
        {
            _db = db;
        }

        public IActionResult Index()
        {
            return View();
        }
        
    }
}

データ作成

_db.Stores.Add(new Store{ Location = new Point(139.768773, 35.680456){ SRID = 4326} });

SRIDを指定しないとエラーになります
この例では4326(世界測地系)を指定しています

空間検索

var stores = _db.Stores.Where(s => s.Location.Intersects(new Point(139.768773, 35.680456) {SRID = 4326})).ToList();