EF core 使用空间数据的方法

.net core 使用空间数据比framework麻烦了不少,将方法搬运过来方便查找

使用的库

Microsoft.EntityFrameworkCore.SqlServer
Microsoft.EntityFrameworkCore.SqlServer.NetTopologySuite

Tip: 此处以SQL Server作为例子,如果使用其他数据库,重点在于引用其他数据库的NetTopologySuite包, 如下图适用于postgreSQL的包

Startup.cs

public void ConfigureServices(IServiceCollection services)
{
    services.AddEntityFrameworkSqlServer()
             .AddDbContext<YourDbContext>(options => options.UseSqlServer(_configuration.GetConnectionString("SqlServer"),
              //映射到空间数据的数据库中的类型在模型中使用 NTS 类型
              x => x.UseNetTopologySuite()));
}

Tip:这里作者使用了services.AddEntityFrameworkSqlServer(),没看懂是做什么用的,微软的解释是:

将实体框架 Microsoft SQL Server 数据库提供程序所需的服务添加到 IServiceCollection 。

在生成大多数应用程序(包括使用 ASP.NET 或其他地方的依赖项注入的应用程序)时,不再需要调用此方法。 仅当生成用于方法的内部服务提供程序时,才需要使用此 UseInternalServiceProvider(IServiceProvider) 方法。 对于某些高级方案,不建议这样做。

以前都是直接serives.AddDbContext,所以上面的方法我删了

建表需要注意:Geography or geometry

SQL Server默认的数据类型是geography,如果要使用geometry,需要声明
比如使用geoserver,不识别geography,则需要geometry

[Column(TypeName = "geometry")]
public Polygon Shape { get; set; }

参考资料

Tip:目前还没有在后端进行空间分析的需求,所以只测试到这个位置,下面的代码就没有经过测试了。 

新增/修改数据

Tip:针对新建数据我遇到一个问题
        [HttpPost]
        public async Task<ActionResult<Tree>> PostTree(Tree tree)
        {
            _context.Tree.Add(tree);
            await _context.SaveChangesAsync();

            return CreatedAtAction("GetTree", new { id = tree.ID }, tree);
        }

        public class Tree
        {
            public int ID { get; set; }
            
            public string Name { get; set; }

            [Column(TypeName = "geometry")]
            public Point Geometry { get; set; }
        }

我使用上图post请求时,传入json无法转换为Tree类,经测试是geometry字段无法转换为Point类,尝试将内置json解析包换喂json.net还是不行

//srid=4326:wgs84
var geometryFactory = NtsGeometryServices.Instance.CreateGeometryFactory(srid: 4326);
var currentLocation = geometryFactory.CreatePoint(new Coordinate(x, y));

线 

//LinearRing的点必须形成一个封闭的线串,而LineString则不需要
var line = new NetTopologySuite.Geometries.LineString(new Coordinate[]
{
    new Coordinate(10,0),
    new Coordinate(10,10),
    new Coordinate(0,10),
    new Coordinate(0,0),
    //new Coordinate(10,0),
});
//设置坐标系
line.SRID = srid;

 面

var geom = new NetTopologySuite.Geometries.Polygon(
    new LinearRing(new Coordinate[]
    {
        //逆时针绘制
        new Coordinate(10,0),
        new Coordinate(10,10),
        new Coordinate(0,10),
        new Coordinate(0,0),
        new Coordinate(10,0),
    }));
//设置坐标系
geom.SRID = srid;

查询数据

概念

GeoJSON:一种地理数据的描述格式。GeoJSON可以描述的对象包括:几何体,要素和要素集。(相关资料)
使用GepJSON需要引用一个新库

GeoJSON.Net

WKT(Well-known text):一种文本标记语言,用于表示矢量几何对象、空间参照系统及空间参照系统之间的转换。它的二进制表示方式,亦即WKB(well-known-binary)则胜于在传输和在数据库中存储相同的信息。该格式由开放地理空间联盟(OGC)制定。WKT可以表示的几何对象包括:点,线,多边形,TIN(不规则三角网)及多面体。(相关资料)
Geometry/geojson/WKT 三者可以互转

//Geometry to GeoJSON
Position position = new Position(x, y);
GeoJSON.Net.Geometry.Point point = new GeoJSON.Net.Geometry.Point(position);
var s = JsonConvert.SerializeObject(point);
//Geometry to wkt
var s2= NetTopologySuite.IO.WKTWriter.ToPoint(city.Location.Coordinate);

结果

"GeoJSON结果:{\"type\":\"Point\",\"coordinates\":[10.0,100.0]},WKT结果:POINT(100 10)"

线 

//Geometry to GeoJSON
var coordinates = new List<IPosition>();
foreach (var item in road.Line.Coordinates)
{
    coordinates.Add(new Position(item.X, item.Y, item.Z));
}
GeoJSON.Net.Geometry.LineString line = new GeoJSON.Net.Geometry.LineString(coordinates);
var s= JsonConvert.SerializeObject(line);
//Geometry to wkt
var s2 = NetTopologySuite.IO.WKTWriter.ToLineString(road.Line.CoordinateSequence);

结果

"GeoJSON结果:{\"type\":\"LineString\",\"coordinates\":[[0.0,10.0,\"NaN\"],[10.0,10.0,\"NaN\"],[10.0,0.0,\"NaN\"],[0.0,0.0,\"NaN\"]]},WKT结果:LINESTRING(10 0, 10 10, 0 10, 0 0)"

面 

//Geometry to GeoJSON
var lines = new List<GeoJSON.Net.Geometry.LineString>();
var polygon = country.Border as NetTopologySuite.Geometries.Polygon;
List<Coordinate[]> res = new List<Coordinate[]>();
res.Add(polygon.Shell.Coordinates);
foreach (ILineString interiorRing in polygon.InteriorRings)
{
    res.Add(interiorRing.Coordinates);
}
foreach(var line in res)
{
    var coordinates = new List<IPosition>();
    foreach (var item in line)
    {
        coordinates.Add(new Position(item.X, item.Y, item.Z));
    }
    lines.Add(new GeoJSON.Net.Geometry.LineString(coordinates));
}
GeoJSON.Net.Geometry.Polygon jsonPolygon = new GeoJSON.Net.Geometry.Polygon(lines);
var s = JsonConvert.SerializeObject(jsonPolygon);
//Geometry to wkt
//点和线的是静态方法,面的是方法_(:з」∠)_
var writer = new NetTopologySuite.IO.WKTWriter();
var s2 = writer.Write(country.Border);

结果

"GeoJSON结果:{\"type\":\"Polygon\",\"coordinates\":[[[0.0,10.0,\"NaN\"],[10.0,10.0,\"NaN\"],[10.0,0.0,\"NaN\"],[0.0,0.0,\"NaN\"],[0.0,10.0,\"NaN\"]]]},WKT结果:POLYGON ((10 0, 10 10, 0 10, 0 0, 10 0))"

计算

计算点与点之间的距离

var distance= NetTopologySuite.Operation.Distance.DistanceOp.Distance(point1, point2);

点是否包含在面以内 

var prepGeom = NetTopologySuite.Geometries.Prepared.PreparedGeometryFactory.Prepare(geom);
var isContain = prepGeom.Contains(point);

经纬度Longitude && Latitude

sql server

Coordinates in NTS are in terms of X and Y values. To represent longitude and latitude, use X for longitude and Y for latitude. Note that this is backwards from the latitude, longitude format in which you typically see these values.
简单来说,X是longitude(经度),Y是latitude(纬度)

geojson

geojson则是相反的

public Position(double latitude, double longitude, double? altitude = null)

示例代码 

      官方示例:

入门 ·NetTopologySuite/NetTopologySuite Wiki (github.com)icon-default.png?t=LA92https://github.com/NetTopologySuite/NetTopologySuite/wiki/GettingStarted

      原作示例:

示例代码https://github.com/zLulus/NotePractice/blob/dev3/Website/DotNetCore/CoreWebsite/Controllers/SqlServerUseGeometryController.cs

参考资料

空间数据
空间类型 - geometry (Transact-SQL)
NTS Topology Suite
空间数据 (SQL Server)

引用来源:

sql server & .net core 使用空间数据https://www.cnblogs.com/Lulus/p/10408633.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值