SQL Server 2008中存储的空间数据,除了能够直接基于SQL Server做空间查询、空间分析外,由于SQLCLR提供了非常丰富、完善的开发API,使得空间数据可以在不同的常用空间数据类型之间转换,同时还可以非常简单的和地图应用无缝集成使用。本篇博文以Bing Maps Silverlight Control为地图应用客户端为基础,介绍如何实现在Bing Maps中呈现地理空间数据。
一、准备空间数据
为了演示如何基于Bing Maps Silverlight Control来呈现SQL Server 2008中存储的空间数据,首先需要在数据库中模拟一些数据供数据查询使用,随意创建一个带有空间数据类型字段的表就可以,如下SQL脚本。
[ID] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](50) NOT NULL,
[Polygon] [geography] NOT NULL)
GO
对于上面脚本所创建的表格,随意的构造几条数据,如下图SQL Server Management Studio的空间结果中所呈现的效果。
二、编写数据服务接口
数据结构使用WebService或者WCF提供都可以,本篇选用WCF Service提供地图数据访问接口,实现将数据库的空间数据读取出来返回到Bing Maps的地图客户端。由于目前的Linq To Sql和ASP.NET Entity Framewrok还不支持SQL Server 2008的空间数据类型,数据访问只能自己编写ADO.NET实现。如下代码块:
{
string cstring = ConfigurationManager.ConnectionStrings["BingMapsDB"].ConnectionString;
SqlConnection conn = new SqlConnection(cstring);
if (conn.State == ConnectionState.Closed) conn.Open();
SqlDataAdapter adapter = new SqlDataAdapter(sql, conn);
DataSet ds = new DataSet();
adapter.Fill(ds);
return ds.Tables[0];
}
直接在WCF中对外公布一个公共方法,并将其标记为操作契约(OperationContract)就完成了服务接口的提供,该接口实现数据库查询并将数据库数据数据组合为对象集合返回到客户端,详细实现如下代码块。
public List<DrawnPolygons> QueryPolygons()
{
var sql = "SELECT * FROM [DrawnPolygons]";
var result = Query(sql);
List<DrawnPolygons> areas = null;
if (result != null && result.Rows.Count > 0)
{
areas = new List<DrawnPolygons>();
foreach (DataRow row in result.Rows)
{
areas.Add(new DrawnPolygons
{
ID = int.Parse(row["ID"].ToString()),
Name = row["NAME"].ToString(),
Xaml = ToXaml(row["Polygon"], row["ID"].ToString())
});
}
}
return areas;
}
接口使用了数据传输对象DrawnPolygons,其他结构如下定义:
public class DrawnPolygons
{
[DataMember]
public int ID { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public string Xaml { get; set; }
}
三、构造空间数据客户端对象
在这里请大家讲视眼转移到本篇前面代码片段的中加粗大红字体处,会发现使用了一个名为“ToXaml()”的方法,此方法的主要功能就是实现将空间数据转换为客户端Silverlight能够识别的xaml语言标记。该方法的详细实现如下代码块所示:
{
StringBuilder sb = new StringBuilder();
//将数据库查询出的空间数据构造为SQL Server空间数据类型对象
var geo = SqlGeography.STGeomFromText(
new SqlChars(
new SqlString(polygon.ToString())), 4326);
//将空间数据构造为Bing Maps图形(多边形)对象的Xaml文本,以返回到客户端直接解析Xaml为Silverlight程序中的对象。
for (int j = 1; j <= geo.NumRings(); j++)
{
if (geo.RingN(j).STNumPoints() > 1)
{
sb.Append("<m:MapPolygon xmlns:m=\"clr-namespace:Microsoft.Maps.MapControl;assembly=Microsoft.Maps.MapControl\"");
sb.Append(" Fill=\"Red\" Locations=\"");
for (int k = 1; k <= geo.RingN(j).STNumPoints(); k++)
{
if (k > 1) sb.Append(" ");
sb.Append(String.Format("{0:0.#####},{1:0.#####}",
(double)geo.RingN(j).STPointN(k).Lat,
(double)geo.RingN(j).STPointN(k).Long));
}
sb.AppendLine("\"/>");
}
}
return sb.ToString();
}
实际上,在服务端将空间数据转化为Xaml并非实现传递空间数据到客户端并解析呈现到GIS界面的唯一选择,还可以将数据库空间数据处理为KML、GML等常用的其它能够表示存储地图数据的任意格式返回到客户端使用。这里为何选择将空间数据解析为Xaml语言标记的目的是为了Silverlight能够直接将Xaml语言标记解析为对应的对象,并能够直接使用。如果选择将空间数据解析为别的地图数据格式,还需要额外的解析算法去实现空间数据的解析。
四、Bing Maps客户端的实现
Bing Maps Silverlight客户端只需要调用上面提供的WCF Service接口,将空间数据查询到客户端,然后通过XamlReader的接口解析Xaml为对应的对象即可,可以在应用程序加载时就发起对接口的调用。如下代码块所示:
{
InitializeComponent();
//调用WCF服务接口查询空间数据到客户端
DataServiceClient service = new DataServiceClient();
service.QueryPolygonsCompleted += new EventHandler<QueryPolygonsCompletedEventArgs>(service_QueryPolygonsCompleted);
service.QueryPolygonsAsync();
}