ThinkGeo.com    |     Documentation    |     Premium Support

Get the shape coreponding to a specific row from dbf file

Hi,


I have a shapefile and I want to find the Feature having a specific value on a column from the dbf file (for example to get the shape coreponding to the row having the value '92154' on first column). I am searching for the fastest way to do that. One way is to call QueryTools.GetFeaturesContaining() because I know the central point of the shape (LAT, LON), but this is very slow. I can perform a query ShapeFileLayer.ExecuteSqlQuery, but this will return me just the row from dbf, not the shape. So what i want is to get the shape coresponding to that specific row, but I don't know how. Can you please help me? 


Best Regards, Cristian.



Christian, 
  
   This is an old problem with shape files.  The records in the DBF rows correspond to the position of the record in the shape file itself.  This means that the third record in the shape file is the third row in the DBF.  The problem is that SQL by nature doesn’t return the absolute record position in the table so you never know what record to fetch.  What you need to is add a new column to the DBF and sequentially number it from 1 to n number of records.  That way when you do the SQL query you can return that row as well.  With this record number you can use the QueryById method on the QueryTools to quickly find the shape.  In the 2.0 version we had an API called something like BuildIndexColumn where we added the column called RecId or something and did the numbering for you.  I didn’t find it on the 3.0 stuff so I will add a ticket to add that API in the future.  If you need help adding the column and updating it let me know and maybe I can get you some code for this. 
  
 David

If you have some code for it please put it here, as I can't find a way to add a column to an existing shapefile. The only way it seemns to be by creating a new shapefile and copying everething in it, including the new column.






 


Cristian,


    I would be happy to show you a sample.  Just to explain a little bit about how our API works.  The layers that you typically use are a wrapper for a FeatureSource which supplies the data.  The Layer itself like a ShapeFileLayer provides the zoom levels etc but it is the FeatureSource contained in it that is the heart of working with the data.  The FeatureSource is a property of all vector oriented layers and you can get it by code like myShapeFileLayer.FeatureSource.


  One important note is that FeatureSource is really an abstract class so the important APIs that are specific to that type of layer are on the specific FeatureSource.  For example on a ShapefileLayer there  is a FeatureSource but the FeatureSource it returns is really a ShapeFileFeatureSource so to get to the shape file specific stuff you need to cast it as below.  Once you cast it you will find all kinds of useful functions that are shape file related.  We didn't want to full expose them on the ShapeFileLayer as it would have added too many members to the object and we wanted the Layer itself to be easy to use and not so technical.


BuildRecId(@"C:\SomeShapefile.shp","RecId");



        private void BuildRecId(string shapeFileName, string recIdColumnName)

        {

            ShapeFileFeatureSource featureSource = null;



            try

            {

                // Open the shape file

                featureSource = new ShapeFileFeatureSource(shapeFileName, ShapeFileReadWriteMode.ReadWrite);

                featureSource.Open();



                // Check to see if the RecId column exists

                Collection<FeatureSourceColumn> columns = featureSource.GetColumns();

                bool foundRecIdColumn = false;

                foreach (FeatureSourceColumn column in columns)

                {

                    if (string.Compare(column.ColumnName, recIdColumnName, true) == 0)

                    {

                        foundRecIdColumn = true;

                        break;

                    }

                }



                // If the RecId column is not found then we need to add it.

                if (!foundRecIdColumn)

                {

                    featureSource.AddColumnInteger(recIdColumnName.ToUpperInvariant(), 7);

                }



                // Loop through all of the records and update RecId column

                int recordCount = featureSource.GetCount();

                for (int i = 0; i < recordCount; i++)

                {

                    featureSource.UpdateDbfData(i.ToString(), recIdColumnName.ToUpperInvariant(), (i + 1).ToString());                    

                }

            }

            finally

            {

                if (featureSource != null && featureSource.IsOpen)

                {

                    featureSource.Close();

                }

            }

        }


David