Feature Column Headers

Topics: Data Access
May 29, 2007 at 6:56 AM
Edited May 29, 2007 at 6:58 AM
I am having a wonderful time using this project. Thanks to all.

Today I wanted to retrive only Column Header Names from the feature table and display it in a combo box. I used the very crude way of querying a bounding box of 0,0 and 1,1. Obviously I got the result but is there a better way?

This is the code I am using:
SharpMap.Data.FeatureDataSet ds = new SharpMap.Data.FeatureDataSet();
SharpMap.Geometries.BoundingBox bbox = new SharpMap.Geometries.BoundingBox(0, 0, 1, 1);
SharpMap.Data.Providers.ShapeFile shp = new SharpMap.Data.Providers.ShapeFile(strLayerPath);
shp.ExecuteIntersectionQuery(bbox, ds);
for (int i = 0; i < ds.Tables[0].Columns.Count; i++)

May 29, 2007 at 7:16 AM
You mean extracting names from all features? You could iterate on every Row, extracting the field you need... but remember that this kind of extraction can be quite slow, since every time the source will be queried for headers names and will create the DataTable.
I use mainly Ogr provider, and I found that in such a case it's better to implement your own functions using the undelying Ogr object, since its like 4-5 times faster.
May 29, 2007 at 9:28 AM
Edited May 29, 2007 at 12:05 PM
No, I don't want to extract names of all features. Just their column header names.

Say my Shape File has the following fields in its dbf file:
Name, Population, Area.

Then while loading the form, I want to load these field names in a combo box.

I could use Ogr provider but I'll save it for other complicated vector features. But certainly querying the way I am doing is taking long time.

Thanks for your idea anyways.
Jun 1, 2007 at 12:20 PM
Any other idea to fill the combo box with the dbf column headers?
Jun 1, 2007 at 5:10 PM
I am only looking at 2.0 alpha but I had the same question... the columns are defined and stored in the shapefile object but I don't know how to access them yet. Can't find a public method.

Instead of querying I read the first feature, like this

SharpMap.Data.Providers.ShapeFile shapefile = new SharpMap.Data.Providers.ShapeFile(pathname);
SharpMap.Data.FeatureDataRow row = shapefile.GetFeature(0);

then you get the columns in row.Table.Columns

Anyway this works in 2.0
If anyone knows how to access the columns already stored in the shapefile object please let me know!
Jun 2, 2007 at 7:47 AM
Its working in 0.9 too. But is taking 4 to 5 seconds for 20MB file.

If I don't get any other idea, I am planning to read dbf file directly like an Excel Sheet. Since its only reading, there is no harm.
Jun 4, 2007 at 5:43 PM
The code is already there in 2, I can read it but I am not a very good C# programmer yet.
Using it is my task for today.

DbaseHeader.cs reads the columns and stores them internally, all I have to do is figure out the proper way C# to
expose the DbaseField Columns at the ShapeFile level.
Jun 19, 2007 at 8:47 AM
All the code in v2.0 to read and parse the DBF file (which stores the ShapeFile attributes) is internal to the data provider, since there isn't a supported scenario to get the schema of the attributes outside the context of a spatial query.

Perhaps if you could explain a little more about why you need the schema without knowing the extents, I could help you better.
Jul 10, 2007 at 4:33 PM
This is a method that I used to spit out column names:

public String ReadDBFWithSharpMap() {
String path = HttpContext.Current.Server.MapPath(@"App_Data\")+ <shapefileName>;
SharpMap.Data.Providers.ShapeFile shapefile = new SharpMap.Data.Providers.ShapeFile(path);
SharpMap.Data.FeatureDataRow row = shapefile.GetFeature(0);
String columns = "";
for (int i = 0; i < row.Table.Columns.Count; i++) {
columns += row.Table.Columnsi.ColumnName +"<br />";

return columns;
Jul 18, 2007 at 1:19 AM

There are many, many, reasons for wanting to verify the schema of data sources w/o actually doing any geometry data processing. I'm looking at switching to SharpMap from tools like MapObjects and apSIS. Those tools provided access to the schema in a standard manner. I use that abiliity for doing things like requested here... populating a combo box of options a user might want to use for theming a map. We also have functions that append several small shapefiles into large one, and you need to verify the same schema on all small files before you proceed. Things like that. Hope that was the kind of info you were looking for.

We are migrating from COM development to .Net development, so I'm taking the opportunity to see if SharpMap might be a good option to older but very powerful COM components that we have been using.
Aug 1, 2007 at 11:39 AM

What is this "standard manner"? Was it tool-specific or an OGC spec?

I'm trying to bring the 2.0 API to a relative freeze point, and if there is a compelling pattern established for getting layer attribute schema I'd consider adopting it.

Otherwise, looking at the columns of a FeatureDataTable which gets filled from an empty query is a fair way to do it. It's a fair way that schema is inferred in non-spatial data-access scenarios on ADO.Net, so it would be familiar to anyone who comes from that experience.
Aug 1, 2007 at 3:46 PM
"Standard" was probably not a good choice of words. What I meant was that there is a recordset interface associated with a layer, and the recordset interface supports common recordset operations... a fields collection that defines the feature data columns... movefirst, movenext, and move-to-bookmark navigation functions, etc. This recordset interface is available to work with any datasource... shapefile, mid/mif, oracle, etc, etc... That is what I meant by "standard". Is there any kind of an interface like this that one can use to access the data in a dataset in a tabular manner? We have a lot of places in our application where we iterate through the recordsets that underly the layers display on a map, or in many cases... simply processed for spatial operations w/o display.

Is anyone interested in a Shapefile provider, for instance, that exposes this kind of functionality (if it doesn't already exist... I'm still exploring SharpMap).
Aug 1, 2007 at 4:54 PM
The DataSet, in .Net, is just this interface. When you issue a query, you are returned a DataTable which has all the attributes in a table object. You iterate it back and forth, change values and send it back to the server for processing. It's basically the disconnected recordset of ADO, with much more functionality (change tracking, indexing, SQL-like selection).

When you execute a query against an IProvider datasource, you get a DataTable. It has the schema in it. What doesn't exist is a way to query the schema info outside of the context of a query, but there isn't much support given to this in generic MS data access methods in both .Net or COM (1). If I want the schema for a table given a connection, a table name and a Recordset, I'd issue an empty query and read back the Fields collection of the Recordset object. With a DataTable, you query and iterate the Columns collection.

(1) Yes, there was OpenSchema() and on the .Net side there is GetSchema, but outside of SQL Server, support for these methods is patchy. Further, these methods only work on a logical database structure level: I can only get schema about tables and views, not about projections onto those tables. One could counter that in a Layer-bound data model like maps are, there really isn't much projection across tables, and I'd have to concede this point. However, this is what causes me to hesitate to introduce a new schema-access design, since there isn't much to base it on... unless you know of a model that we could adopt.
Aug 1, 2007 at 9:05 PM
Thank you for the explanation. I've just started to review the use of your FeatureDataset. It appears to inherit from the standard Dataset, and in the FeatureTable, carry a collection of matching geometry objects? But it doesn't implement an IProvider interface, so cannot be used as a stand-alone in-memory provider, right?

So, when the map is rendering from a datasource, it appears that the datasource responds to an envelope query, and returns a FeatureDataset that is an extracted subset of the datasource? The datasources have no data access mechanism other than the FeatureDataset query response?

I guess I was hoping that a provider would implement a Dataset or FeatureDataset and provide direct data access w/o a need to copy its data to another object (and granted, for the purposes of getting the schema, it is a fast empty query).

I have an in-memory dataset with a single table and 30,000 records that usually all need to be drawn (closely spaced values collected from a slow-moving machine in a confined area). So, I can easily implement an IProvider interface on my dataset. When the entire dataset is to be displayed, does it make sense for me to copy my datset to a FeatureDataset, or is there some way to efficiently use the existing underlying dataset. In other words, have you considered making the FeatureDataset be an interface, or defining an IFeatureDataset interface to be implemented by the FeatureDataset and any other Dataset/Provider that can efficiently implement it?

I'm sorry... I have taken us off-topic here... but I was going to be asking a lot of questions about the the roles of the FeatureDataSet vs. the IProvider interface later this week, anyway :) Feel free to move the post.
Aug 1, 2007 at 11:18 PM
Basically, the relationship between a FeatureDataSet and an IProvider instance is similar to a regular DataSet and a TableAdapter. In a way, IProvider is like a TableAdapter because it adapts the datasource with a common interface and is used to pull data into a DataSet. A TableAdapter is also able to synchronize changes in the disconnected DataSet back into the data source, whereas an IProvider is not able to - it is read-only (in v0.9/1.0).

The key to understanding the relationship is to observe how much of the design of ADO.Net is geared towards disconnected operation. In ADO, it was mostly an afterthought, and this is why ADODB.RecordSet became crammed with methods that allowed it to act as a cursor, connect to a database, create command objects on the fly, execute the commands and marshal the results as well as craft up a new one from code and fill it with whatever you want (XML data became popular). In ADO.Net, this is all factored out into 2 main classes: DataSet and DataReader. A TableAdapter is the class that allow these two classes to interact in a way which gives you the functionality you are familiar with in the RecordSet. Yet the main story is one of disconnected data: you get a TableAdapter (or a Connection and Command if you want to do it manually), create a new DataSet, ask the TableAdapter to fill it, and you have a client-side set of data to work with.

This pattern is what has been used as guidance in designing the SharpMap method of data access: you get an IProvider instance, create a FeatureDataSet, ask the IProvider to fill it, using a BoundingBox as the criteria, and you are given back a set of data to work with on the client-side.

As to using the DataSet and FeatureDataSet together, have you tried just using the FeatureDataSet? Since it is a DataSet, you can use it wherever ADO.Net expects one. That way you have just one copy of the data.
Aug 2, 2007 at 1:35 AM
I have sooo much to learn (sigh)...

My assumption was that whenever the map was zoomed in or out, that a new bounding box query would be made to the Provider associated with each layer, so, we would be copying the data from a provider into a FeatureDataSet over and over. Are you telling me that there is a way for me to load a FeatureDataset dynamically and have it be used throughout the map applications, w/o the need for a separate data provider?