C# 或者EF 处理sqlserver 的空间geometry类型

需求:数据库中创建了一个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都是统一一个标准 然后利用里面的方法去构造 在利用里面的方法去比较

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值