第06章-数据提供者详解
第06章:数据提供者详解
6.1 数据提供者概述
6.1.1 IProvider 接口
数据提供者是 SharpMap 访问空间数据的核心组件,所有数据提供者都实现 IProvider 接口:
namespace SharpMap.Data.Providers
{
public interface IProvider : IDisposable
{
// 连接管理
string ConnectionID { get; }
bool IsOpen { get; }
void Open();
void Close();
// 空间参考
int SRID { get; set; }
// 数据范围
Envelope GetExtents();
// 几何查询
Collection<Geometry> GetGeometriesInView(Envelope envelope);
Collection<uint> GetObjectIDsInView(Envelope envelope);
Geometry GetGeometryByID(uint oid);
// 要素查询
void ExecuteIntersectionQuery(Envelope envelope, FeatureDataSet ds);
void ExecuteIntersectionQuery(Geometry geometry, FeatureDataSet ds);
FeatureDataRow GetFeature(uint oid);
// 要素计数
int GetFeatureCount();
}
}
6.1.2 内置数据提供者
SharpMap 提供了多种内置数据提供者:
| 提供者 | 数据格式 | 包 |
|---|---|---|
| ShapeFile | ESRI Shapefile | SharpMap |
| PostGIS | PostgreSQL/PostGIS | SharpMap |
| MsSql | SQL Server Spatial | SharpMap |
| MsSqlSpatial | SQL Server Geometry | SharpMap |
| Oracle | Oracle Spatial | SharpMap |
| Spatialite | Spatialite | SharpMap |
| Ogr | GDAL/OGR 支持的格式 | SharpMap.Extensions |
| WMS | WMS 服务 | SharpMap |
| GeoPackage | OGC GeoPackage | SharpMap.Extensions |
6.2 ShapeFile 数据提供者
6.2.1 基本使用
using SharpMap.Data.Providers;
// 创建 ShapeFile 提供者
var provider = new ShapeFile("data/countries.shp");
// 使用文件索引(.shx 文件)
var provider2 = new ShapeFile("data/countries.shp", true);
// 使用空间索引(自动创建或读取 .sidx 文件)
var provider3 = new ShapeFile("data/countries.shp", true, true);
// 基本操作
provider.Open();
Console.WriteLine($"要素数量:{provider.GetFeatureCount()}");
Console.WriteLine($"数据范围:{provider.GetExtents()}");
Console.WriteLine($"SRID:{provider.SRID}");
provider.Close();
6.2.2 读取属性结构
var provider = new ShapeFile("data/countries.shp", true);
provider.Open();
// 获取 DBF 文件的字段结构
var table = new FeatureDataTable();
provider.ExecuteIntersectionQuery(provider.GetExtents(), new FeatureDataSet { Tables = { table } });
foreach (DataColumn column in table.Columns)
{
Console.WriteLine($"字段:{column.ColumnName}");
Console.WriteLine($" 类型:{column.DataType}");
Console.WriteLine($" 允许空:{column.AllowDBNull}");
}
provider.Close();
6.2.3 查询数据
var provider = new ShapeFile("data/countries.shp", true);
provider.Open();
// 范围查询
var envelope = new Envelope(-180, 180, -90, 90);
var geometries = provider.GetGeometriesInView(envelope);
Console.WriteLine($"范围内几何数量:{geometries.Count}");
// 获取要素数据
var featureDataSet = new FeatureDataSet();
provider.ExecuteIntersectionQuery(envelope, featureDataSet);
if (featureDataSet.Tables.Count > 0)
{
var table = featureDataSet.Tables[0];
foreach (FeatureDataRow row in table.Rows)
{
Console.WriteLine($"名称:{row["NAME"]}");
Console.WriteLine($"几何类型:{row.Geometry.GeometryType}");
}
}
// 按 ID 获取单个要素
var feature = provider.GetFeature(0);
if (feature != null)
{
Console.WriteLine($"第一个要素:{feature.Geometry.AsText()}");
}
provider.Close();
6.2.4 空间索引
// 创建空间索引
public static void CreateSpatialIndex(string shapefile)
{
var provider = new ShapeFile(shapefile, true, true);
provider.Open();
// 如果没有索引,SharpMap 会自动创建
// 索引文件保存为 .sidx
provider.Close();
}
// 手动创建索引
public static void RebuildSpatialIndex(string shapefile)
{
var indexFile = Path.ChangeExtension(shapefile, ".sidx");
if (File.Exists(indexFile))
{
File.Delete(indexFile);
}
// 重新创建索引
var provider = new ShapeFile(shapefile, true, true);
provider.Open();
provider.Close();
}
6.2.5 编码设置
// 设置 DBF 文件编码(处理中文等非 ASCII 字符)
var provider = new ShapeFile("data/china.shp", true);
provider.Encoding = Encoding.GetEncoding("GB2312"); // 或 "GBK"
// 或使用 UTF-8
provider.Encoding = Encoding.UTF8;
6.3 PostGIS 数据提供者
6.3.1 基本配置
using SharpMap.Data.Providers;
// 连接字符串
string connectionString = "Host=localhost;Port=5432;Database=gisdb;Username=postgres;Password=123456";
// 创建 PostGIS 提供者
// 参数:连接字符串, 表名, 几何列, 主键列
var provider = new PostGIS(connectionString, "countries", "geom", "gid");
// 设置 SRID
provider.SRID = 4326;
// 使用
var layer = new VectorLayer("PostGIS Countries", provider);
map.Layers.Add(layer);
6.3.2 高级配置
// 创建带过滤条件的提供者
var provider = new PostGIS(connectionString, "countries", "geom", "gid")
{
SRID = 4326,
DefinitionQuery = "population > 1000000" // SQL WHERE 条件
};
// 指定要返回的字段
provider.DefinitionQuery = "continent = 'Asia'";
// 使用视图
var viewProvider = new PostGIS(connectionString, "v_large_countries", "geom", "gid");
// 使用 SQL 查询
var sqlProvider = new PostGIS(
connectionString,
"(SELECT gid, name, geom FROM countries WHERE population > 1000000) AS subquery",
"geom",
"gid");
6.3.3 PostGIS 函数
// 使用 PostGIS 函数查询
public static FeatureDataTable QueryWithinDistance(
string connectionString,
Coordinate center,
double distanceMeters)
{
using (var conn = new NpgsqlConnection(connectionString))
{
conn.Open();
string sql = @"
SELECT *, ST_Distance(geom::geography, ST_MakePoint(@x, @y)::geography) as distance
FROM cities
WHERE ST_DWithin(geom::geography, ST_MakePoint(@x, @y)::geography, @distance)
ORDER BY distance";
using (var cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("x", center.X);
cmd.Parameters.AddWithValue("y", center.Y);
cmd.Parameters.AddWithValue("distance", distanceMeters);
var table = new DataTable();
using (var adapter = new NpgsqlDataAdapter(cmd))
{
adapter.Fill(table);
}
return ConvertToFeatureDataTable(table);
}
}
}
6.4 SQL Server 数据提供者
6.4.1 MsSql 提供者
using SharpMap.Data.Providers;
// 连接字符串
string connectionString = @"Server=localhost;Database=GisDB;Trusted_Connection=True;";
// 创建 SQL Server 提供者
var provider = new MsSql(connectionString, "dbo.Countries", "Shape", "ObjectId");
// 设置 SRID
provider.SRID = 4326;
// 添加 WHERE 条件
provider.DefinitionQuery = "Status = 'Active'";
// 使用
var layer = new VectorLayer("SQL Server Data", provider);
6.4.2 MsSqlSpatial 提供者
// 使用 SQL Server 的 geometry 数据类型
var provider = new MsSqlSpatial(connectionString, "dbo.Parcels", "Shape", "ParcelId");
// 设置几何类型(geography 或 geometry)
provider.GeometryColumnType = SqlGeometryType.Geometry;
// 添加空间索引提示
provider.SpatialHint = "IX_Spatial_Shape";
6.5 OGR 数据提供者
6.5.1 基本使用
// 需要安装 SharpMap.Extensions 和 GDAL
using SharpMap.Data.Providers;
// 打开 GeoJSON 文件
var geoJsonProvider = new Ogr("data/countries.geojson");
// 打开 KML 文件
var kmlProvider = new Ogr("data/places.kml");
// 打开 GML 文件
var gmlProvider = new Ogr("data/features.gml");
// 打开 GPX 文件
var gpxProvider = new Ogr("data/track.gpx");
// 打开 FileGDB(ESRI 文件地理数据库)
var fgdbProvider = new Ogr("data/geodatabase.gdb", 0); // 0 为图层索引
6.5.2 OGR 图层选择
// 打开数据源
var ogrProvider = new Ogr("data/complex.gdb");
// 获取图层列表
var layerNames = Ogr.GetLayerNames("data/complex.gdb");
foreach (var name in layerNames)
{
Console.WriteLine($"图层:{name}");
}
// 按名称打开图层
var namedProvider = new Ogr("data/complex.gdb", "buildings");
// 按索引打开图层
var indexProvider = new Ogr("data/complex.gdb", 2);
6.5.3 支持的格式
OGR 支持众多数据格式,常用的包括:
| 格式 | 扩展名 | 说明 |
|---|---|---|
| GeoJSON | .geojson, .json | JSON 格式的矢量数据 |
| KML | .kml | Google Earth 格式 |
| GML | .gml | OGC GML 格式 |
| GPX | .gpx | GPS 交换格式 |
| FileGDB | .gdb | ESRI 文件地理数据库 |
| GeoPackage | .gpkg | OGC GeoPackage |
| CSV | .csv | 带坐标的 CSV 文件 |
| DXF | .dxf | AutoCAD 交换格式 |
| MapInfo | .tab | MapInfo 格式 |
| SpatiaLite | .sqlite | SQLite 空间数据库 |
6.6 内存数据提供者
6.6.1 GeometryProvider
using SharpMap.Data.Providers;
using NetTopologySuite.Geometries;
// 创建几何集合
var geometries = new List<Geometry>();
var factory = new GeometryFactory();
// 添加点
geometries.Add(factory.CreatePoint(new Coordinate(116.4, 39.9)));
geometries.Add(factory.CreatePoint(new Coordinate(121.5, 31.2)));
geometries.Add(factory.CreatePoint(new Coordinate(113.3, 23.1)));
// 添加线
geometries.Add(factory.CreateLineString(new[]
{
new Coordinate(116.4, 39.9),
new Coordinate(121.5, 31.2),
new Coordinate(113.3, 23.1)
}));
// 创建提供者
var provider = new GeometryProvider(geometries);
// 使用
var layer = new VectorLayer("Memory Data", provider);
6.6.2 GeometryFeatureProvider
using SharpMap.Data.Providers;
using SharpMap.Data;
using NetTopologySuite.Geometries;
// 创建要素集合
var features = new List<Feature>();
var factory = new GeometryFactory();
// 创建要素(带属性)
var feature1 = new Feature
{
Geometry = factory.CreatePoint(new Coordinate(116.4, 39.9)),
Attributes = new AttributesTable
{
{ "Name", "北京" },
{ "Population", 21540000 }
}
};
var feature2 = new Feature
{
Geometry = factory.CreatePoint(new Coordinate(121.5, 31.2)),
Attributes = new AttributesTable
{
{ "Name", "上海" },
{ "Population", 24280000 }
}
};
features.Add(feature1);
features.Add(feature2);
// 创建提供者
var provider = new GeometryFeatureProvider(features);
// 使用
var layer = new VectorLayer("Feature Data", provider);
6.6.3 DataTablePoint 提供者
using SharpMap.Data.Providers;
// 创建数据表
var dataTable = new DataTable();
dataTable.Columns.Add("ID", typeof(int));
dataTable.Columns.Add("Name", typeof(string));
dataTable.Columns.Add("X", typeof(double));
dataTable.Columns.Add("Y", typeof(double));
// 添加数据
dataTable.Rows.Add(1, "北京", 116.4, 39.9);
dataTable.Rows.Add(2, "上海", 121.5, 31.2);
dataTable.Rows.Add(3, "广州", 113.3, 23.1);
// 创建点数据提供者
var provider = new DataTablePoint(dataTable, "ID", "X", "Y");
// 使用
var layer = new VectorLayer("Cities", provider);
layer.Style = new VectorStyle
{
PointColor = Brushes.Red,
PointSize = 10
};
6.7 自定义数据提供者
6.7.1 基本实现
using System.Collections.ObjectModel;
using SharpMap.Data;
using SharpMap.Data.Providers;
using NetTopologySuite.Geometries;
public class CustomProvider : IProvider
{
private readonly List<Feature> _features;
private readonly GeometryFactory _factory;
private bool _isOpen;
public CustomProvider()
{
_features = new List<Feature>();
_factory = new GeometryFactory();
}
public string ConnectionID => "CustomProvider";
public bool IsOpen => _isOpen;
public int SRID { get; set; } = 4326;
public void Open() => _isOpen = true;
public void Close() => _isOpen = false;
// 添加要素
public void AddFeature(Geometry geometry, IDictionary<string, object> attributes)
{
var feature = new Feature
{
Geometry = geometry,
Attributes = new AttributesTable(attributes)
};
_features.Add(feature);
}
public Envelope GetExtents()
{
if (_features.Count == 0)
return new Envelope();
var env = new Envelope();
foreach (var feature in _features)
{
env.ExpandToInclude(feature.Geometry.EnvelopeInternal);
}
return env;
}
public Collection<Geometry> GetGeometriesInView(Envelope envelope)
{
var result = new Collection<Geometry>();
foreach (var feature in _features)
{
if (envelope.Intersects(feature.Geometry.EnvelopeInternal))
{
result.Add(feature.Geometry);
}
}
return result;
}
public Collection<uint> GetObjectIDsInView(Envelope envelope)
{
var result = new Collection<uint>();
for (int i = 0; i < _features.Count; i++)
{
if (envelope.Intersects(_features[i].Geometry.EnvelopeInternal))
{
result.Add((uint)i);
}
}
return result;
}
public Geometry GetGeometryByID(uint oid)
{
if (oid < _features.Count)
return _features[(int)oid].Geometry;
return null;
}
public void ExecuteIntersectionQuery(Envelope envelope, FeatureDataSet ds)
{
var table = CreateFeatureDataTable();
for (int i = 0; i < _features.Count; i++)
{
if (envelope.Intersects(_features[i].Geometry.EnvelopeInternal))
{
AddFeatureToTable(table, i);
}
}
ds.Tables.Add(table);
}
public void ExecuteIntersectionQuery(Geometry geometry, FeatureDataSet ds)
{
var table = CreateFeatureDataTable();
for (int i = 0; i < _features.Count; i++)
{
if (geometry.Intersects(_features[i].Geometry))
{
AddFeatureToTable(table, i);
}
}
ds.Tables.Add(table);
}
public FeatureDataRow GetFeature(uint oid)
{
if (oid >= _features.Count)
return null;
var table = CreateFeatureDataTable();
AddFeatureToTable(table, (int)oid);
return table.Rows[0] as FeatureDataRow;
}
public int GetFeatureCount() => _features.Count;
private FeatureDataTable CreateFeatureDataTable()
{
var table = new FeatureDataTable();
if (_features.Count > 0)
{
foreach (var name in _features[0].Attributes.GetNames())
{
var value = _features[0].Attributes[name];
table.Columns.Add(name, value?.GetType() ?? typeof(object));
}
}
return table;
}
private void AddFeatureToTable(FeatureDataTable table, int index)
{
var feature = _features[index];
var row = table.NewRow();
row.Geometry = feature.Geometry;
foreach (var name in feature.Attributes.GetNames())
{
row[name] = feature.Attributes[name];
}
table.AddRow(row);
}
public void Dispose()
{
_features.Clear();
}
}
6.7.2 使用自定义提供者
// 创建自定义提供者
var provider = new CustomProvider();
// 添加数据
var factory = new GeometryFactory();
provider.AddFeature(
factory.CreatePoint(new Coordinate(116.4, 39.9)),
new Dictionary<string, object>
{
{ "Name", "北京" },
{ "Type", "Capital" }
});
provider.AddFeature(
factory.CreatePoint(new Coordinate(121.5, 31.2)),
new Dictionary<string, object>
{
{ "Name", "上海" },
{ "Type", "Municipality" }
});
// 创建图层
var layer = new VectorLayer("Custom Data", provider);
layer.Style = new VectorStyle
{
PointColor = Brushes.Blue,
PointSize = 12
};
map.Layers.Add(layer);
6.7.3 实时数据提供者
public class RealtimeProvider : IProvider
{
private readonly Func<IEnumerable<Feature>> _dataSource;
private List<Feature> _cachedFeatures;
private DateTime _lastUpdate;
private readonly TimeSpan _cacheTimeout;
public RealtimeProvider(Func<IEnumerable<Feature>> dataSource, TimeSpan? cacheTimeout = null)
{
_dataSource = dataSource;
_cacheTimeout = cacheTimeout ?? TimeSpan.FromSeconds(5);
_cachedFeatures = new List<Feature>();
}
private void RefreshCache()
{
if (DateTime.Now - _lastUpdate > _cacheTimeout)
{
_cachedFeatures = _dataSource().ToList();
_lastUpdate = DateTime.Now;
}
}
public Collection<Geometry> GetGeometriesInView(Envelope envelope)
{
RefreshCache();
var result = new Collection<Geometry>();
foreach (var feature in _cachedFeatures)
{
if (envelope.Intersects(feature.Geometry.EnvelopeInternal))
{
result.Add(feature.Geometry);
}
}
return result;
}
// ... 其他接口方法实现类似
}
// 使用实时数据提供者
var realtimeProvider = new RealtimeProvider(() =>
{
// 从 API 或数据库获取实时数据
return FetchVehiclePositions();
});
var layer = new VectorLayer("Vehicles", realtimeProvider);
map.VariableLayers.Add(layer); // 添加到动态图层集合
6.8 数据提供者性能优化
6.8.1 使用空间索引
// ShapeFile 使用空间索引
var provider = new ShapeFile("data.shp", true, true); // 第三个参数启用空间索引
// PostGIS 确保有空间索引
// CREATE INDEX idx_geom ON table USING GIST(geom);
// SQL Server 确保有空间索引
// CREATE SPATIAL INDEX idx_geom ON table(geom);
6.8.2 限制返回字段
// PostGIS 只返回需要的字段
var provider = new PostGIS(connectionString,
"(SELECT gid, name, geom FROM countries) AS subquery",
"geom", "gid");
// 减少网络传输和内存使用
6.8.3 使用数据缓存
public class CachedProvider : IProvider
{
private readonly IProvider _innerProvider;
private readonly Dictionary<string, object> _cache;
private readonly TimeSpan _cacheExpiration;
public CachedProvider(IProvider innerProvider, TimeSpan? expiration = null)
{
_innerProvider = innerProvider;
_cache = new Dictionary<string, object>();
_cacheExpiration = expiration ?? TimeSpan.FromMinutes(5);
}
public Envelope GetExtents()
{
string key = "extents";
if (!_cache.ContainsKey(key))
{
_cache[key] = _innerProvider.GetExtents();
}
return (Envelope)_cache[key];
}
// ... 实现其他缓存逻辑
}
6.9 本章小结
本章详细介绍了 SharpMap 的数据提供者系统:
- IProvider 接口:了解了数据提供者的核心接口定义
- ShapeFile:掌握了 Shapefile 文件的读取和查询
- PostGIS:学习了 PostGIS 数据库的连接和使用
- SQL Server:了解了 SQL Server 空间数据的访问
- OGR:掌握了通过 OGR 访问多种数据格式
- 内存提供者:学习了内存数据的使用方法
- 自定义提供者:了解了如何实现自定义数据提供者
- 性能优化:掌握了数据提供者的优化技巧
6.10 参考资源
下一章预告:第07章将详细介绍 SharpMap 的样式系统和主题渲染,包括唯一值渲染、分级渲染等高级样式配置。

浙公网安备 33010602011771号