需求:数据库中创建了一个grometry空间对象 是一个Polygon区域 需要在c#中根据获得的坐标X,Y 来判断是否在这个区域中
首先简单了解一下grometry 数据库对象 也就是类似在数据库画图工具 画出点 线 面这种 point linestring Polygon 图形
详细官网介绍类型 空间数据类型概述 - SQL Server | Microsoft Learn
这里有数据库相关 画图的 操作实列。画图的手法说明是 wtk 画好之后 存表的是 空间标识符 srid 这不是重点!
重点是怎么把数据库的空间对象为我c#所用 !!
那么我现在就要讲一下 对于grometry c#有一个对应的 sqlgrometry类型
就是需要引用using Microsoft.SqlServer.Types; 以及nuget里面去下载Microsoft.SqlServer.Types
引用了之后 我们的操作 其实就是 将grometry 转化为 sqlgrometry
1:操作也很简单就是 利用sql的基础对象 连接 命令 到 reder的时候 利用sqlgrometry 反序列化出来
下面代码示例 应该很容易明白
string connstring = "Data Source=1234;Initial Catalog=data;User ID=sa;Password=Password01!;";
public SqlConnection GetSQLConnection()
{
try
{
return new SqlConnection(connstring);
}
catch (Exception)
{
return null;
}
}
public SqlCommand GetCommand(string sql)
{
SqlConnection conn = GetSQLConnection();
conn.Open();
SqlCommand cmd = new SqlCommand(sql, conn);
return cmd;
}
public SqlGeometry GetGeometry(string sql)
{
try
{
SqlCommand cmd = GetCommand(sql);
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
SqlBytes sb = reader.GetSqlBytes(0);
//Deserialize方法只有引用SQLServer2012的dll才能使用,2008不支持
SqlGeometry g = SqlGeometry.Deserialize(sb);
return g;
}
return null;
}
catch (Exception e)
{ return null; }
}
之后就写一下sql 语句调用一下 就得到sqlgrometry类型了
注意!sql语句就是你那个对应空间类型的 列 也就是 空间标识符那列 0*E13123 一串内容的
string sql = "select Profile from [McsRefine].[dbo].[Common_Zone]";
var region = GetGeometry(sql);
2:现在将数据库的空间类型 通过SqlDataReader 转化了,那么C#本身需要被判断的点 那也要想同的类型才行
也就是说 C#用 数据库空间对象 是 sqlgrometry 那么 c#用比较的点 也要是sqlgrometry
接下来的操作就是将 需要判断的点 也就是坐标 转化sqlgrometry 然后与之前数据库转化的region 比较
SqlGeometry.Point() 创建出来 坐标对应的SqlGeometry 对象
然后利用STIntersects 方法去进行包含操作判断是否在区域中
这些Point STIntersects 方法其实也就是SqlGeometry 复用数据库Geometry 那边的方法
3 总结:说白了就是 数据库Geometry空间的方法函数 c#SqlGeometry 也能照样用
只要是把对象转化成SqlGeometry 去调用就ok了! 数据库的内容就通过第1点 SqlDataReader 转化
C#的数据信息就直接用SqlGeometry对象 创建出来
然后利用函数比较 利用结果
代码实列:
public bool Isregion(List<Patrol_UserGisInfo> list)
{
string sql = "select Profile from [McsRefine].[dbo].[Common_Zone]";
var region = GetGeometry(sql);
foreach (var item in list)
{
var point = SqlGeometry.Point(Convert.ToDouble(item.Longitude), Convert.ToDouble(item.Latitude), 4326);
if (!region.MakeValid().STIntersects(point))
{
return false;
}
}
return true;
}
EF的话 原理相同 有一个 DbGeometry 对象 也是想办法都搞成这个对象然后 进行函数比较
var myLocation = DbGeometry.FromText(string.Format("POINT({0}{1})", item.Longitude, item.Latitude), 4326);
if (!Common_ZoneDao.GetInstance().Entities.Any(t => SqlSpatialFunctions.MakeValid(t.Profile).Intersects(myLocation)))
{
return false;
}
这个列子中 Profile 这个列名字段 EF 声明是就声明成DbGeometry
public System.Data.Entity.Spatial.DbGeometry Profile { get; set; }
C#生成的点坐标X,Y 用DbGeometry.FromText 去构造DbGeometry点对象
然后利用Intersects方法去比较
但是linq使用SqlSpatialFunctions.MakeValid可能会报错
所以呢自己呢用个方法将DbGeometry变有效
public static DbGeometry MakeValid(DbGeometry geom)
{
var wkt = SqlGeometry.STGeomFromText(new SqlChars(geom.AsText()), 0).MakeValid().STAsText().ToSqlString().ToString();
return DbGeometry.FromText(wkt, 0);
}
其实都是转成一个 共同的对象 不论是数据库 创建比较 还是C#创建对象
Geometry DbGeometry SqlGeometry都是统一一个标准 然后利用里面的方法去构造 在利用里面的方法去比较