Developing spatial and attribute queries

ArcGIS Runtime SDK for Windows Mobile allows you to perform spatial and attribute queries for functions such as identify and selection, and to locate features based on field values or spatial constraints. This topic introduces spatial and attribute queries then shows you how to return features from queries.

Queries are performed against features of a given feature source that are currently in the map cache. Since features in the cache may not represent all the features available on the server, you need to consider the content of the cache before performing these queries. If you expect to be doing queries in the field, in a disconnected environment, and want to work against all possible features of a given feature source, you should pre-cache the whole feature source on the device before going to the field. However, if you're working in a connected environment, you can request features from the server, then query the cache using the same query criteria. This is described in the Attribute queries section of this topic.

Queries can return records as a FeatureDataTable, an implementation of an ADO data table, or as a FeatureDataReader (an implementation of an ADO DataReader). FeatureDataReader objects access data much faster than FeatureDataTables but are read-only and can only read data sequentially. Consequently, they are suited for functions such as identify. In comparison, FeatureDataTables are editable, allow random access, and can be bound to other controls such as data grids.

To query data, you need a feature source and a query filter. The query filter contains the spatial and attribute criteria for the query.

Spatial queries

Spatial queries require a filter geometry, such as a polygon, and a geometric relationship enumeration for a given feature layer. For example, return all the records for roads within the current map extent. The geometric relationship enumerations are based on the DE-9IM matrix and include Contain, Cross, Disjoint, Intersect, Overlap, Touch, Within, and Any. The GeometricRelationship class contains more information about these relationships.

The following example shows a spatial query returning a FeatureDataTable. It will find features that are completely contained within an interactive rectangle on the map, then flashes the geometry for the first returned record.

// Mouse down map coordinate 
private Coordinate m_startCoordinate;

// Mouse up map coordinate 
private Coordinate m_endCoordinate;

private void map1_MouseDown(object sender,ESRI.ArcGIS.Mobile.MapMouseEventArgs e) 
{ 
  // Anchor coordinate used to create an envelope to query features 
  m_startCoordinate = e.MapCoordinate; 
} 
private void map1_MouseUp(object sender,ESRI.ArcGIS.Mobile.MapMouseEventArgs e) 
{ 
  // Last coordinate used to create an envelope to query features 
  m_endCoordinate = e.MapCoordinate; 
  // Finds features that are completely contain in the envelope 
  FindFeaturesInEnvelope(); 
} 
private void FindFeaturesInEnvelope() 
{ 
  // Creates a new envelope based on those coordinates 
  Envelope envelope = new Envelope(m_startCoordinate, m_endCoordinate); 

  // Retrieves the first layer in the map
  FeatureSource featureSource = mobileCache1.FeatureSources[0]; 
  if (featureSource == null) 
    return; 

  // Creates a instance of a query filter. Query filter uses the dragged map rectangle and 
  // it will search for all features in layer index = 0, that are contained in this geometry. 
  QueryFilter spatialQueryFilter = new QueryFilter(envelope,  GeometricRelationshipType.Contain); 

  // Querying the feature layer
  FeatureDataTable featureDataTable = featureSource.GetDataTable(spatialQueryFilter); 

  // If feature layer data table has no rows back 
  if (featureDataTable.Rows.Count == 0) 
  {
    MessageBox.Show("No features found"); 
    return; 
  } 

  // If rows back, grabs the first row and geometry column in order to get the feature's geometry 
  // and highlight it in order to locate the feature in the map 
  Geometry geometry = featureDataTable.Rows[0][featureDataTable.GeometryColumnIndex] as Geometry; 

  // if no geometry  
  if (geometry == null) 
    return; 

  // If geometry is valid, the map will rendered it 3 times every 150 milliseconds. 
  map1.FlashGeometry(Pens.Red, (SolidBrush)Brushes.Yellow, 15, 150, 3, geometry); }

The next example shows a spatial query returning a FeatureDataReader. This example shows MapTip functionality by querying the layer display field for each feature under the mouse pointer and displaying the value as a ToolTip.

// FeatureSource to be queried 
private FeatureSource m_toolTipFeatureSource; 

// FeatureSource's display field index
private int m_displayFieldIndex; 

private void map1_MouseMove(object sender, MapMouseEventArgs e) 
{ 
  // If no feature layer, selects the first one 
  if (m_toolTipFeatureSource == null) 
  { 
    // Retrieves the first layer in the map 
    m_toolTipFeatureSource = mobileCache1.FeatureSources[0] ; 
    // Retrieves the layer's display field 
    m_displayFieldIndex = m_toolTipFeatureSource.DisplayColumnIndex; 
  }

  if (m_toolTipFeatureSource == null) 
    return; 

  // Converts 5 pixels to map units 
  double delta = map1.ToMap(5); 

  // Creates an envelope using the current mouse map coordinate as the center 
  // and the delta as the envelope's width and height 
  Envelope envelope = new Envelope(e.MapCoordinate, delta, delta); 

  // Creates a instance of a query filter. Query filter uses the dragged map rectangle and 
  // it will search for all features in layer index = 0, that are contained in this geometry. 
  QueryFilter spatialQueryFilter = new QueryFilter(envelope, GeometricRelationshipType.Intersect); 

  //Querying the feature layer. This requires the use of the using keyword to ensure that the reader will be dispose 
  // It specifies when the reader should be release.  
  using (FeatureDataReader reader = m_toolTipFeatureSource.GetDataReader(spatialQueryFilter, null)) 
  {
  // Moves the cursor to the next record 
  while (reader.Read())  
    //Associates the tooltip to the map control and 
    // sets the tooltip text to be the feature's layer display field value
     toolTip1.SetToolTip(map1, reader.GetValue(m_displayFieldIndex).ToString()); 
  }
}

Attribute queries

Attribute queries are used to select features based on an item value and are performed by providing a where clause and a flag to indicate case sensitivity in a query filter.

The where clause supports the following operators:

The following example shows an attribute query returning a FeatureDataTable. It will search for features that contain the letter 'a' in a certain field and highlight the geometry of the first returned feature:

private void button1_Click(object sender, EventArgs e)
{
   // Retrieves the first layer in the map
  FeatureSource featureSource = mobileCache1.FeatureSources[0];
  if (featureSource == null)
    return; 

  // Creates a where clause string.
  // Use % or * to find a string that contains an a character
  string whereClause = featureSource.DisplayColumnName + " like '%E%'";

  // Creates a instance of a query filter. Query filter can use the dragged map rectangle and
  // it will search for all features in layer index = 0, that are contained in this geometry.
  QueryFilter queryFilter = new QueryFilter(whereClause);

  // Querying the feature layer
  FeatureDataTable featureDataTable = featureSource.GetDataTable(queryFilter);

  // If feature layer data table has no rows back
  if (featureDataTable.Rows.Count == 0)
  {
    MessageBox.Show("No features found");
    return;
  }
  // If rows back, grabs the first row and geometry column in order to get the feature's geometry
  // and highlight it in order to locate the feature in the map
  Geometry geometry = featureDataTable.Rows[0][featureDataTable.GeometryColumnIndex] as Geometry;

  // if no geometry
  if (geometry == null)
    return;

  // If geometry is valid, the map will rendered it 3 times every 150 milliseconds.
  map1.FlashGeometry(Pens.Red, (SolidBrush)Brushes.Yellow, 15, 150, 3, geometry);
}

The following example shows an attribute query returning a FeatureDataReader. It will search for features that contain the letter "a" in a certain field and highlight the geometry of the first returned feature:

private void button1_Click(object sender, EventArgs e)
{
  // Retrieves the first layer in the map
  FeatureSource featureSource = mobileCache1.FeatureSources[0];
  if (featureSource == null)
    return;

  // Creates a where clause string.
  // Use % as the wildcard char for data coming from SDE, and
  // * for data coming from a personal geodatabase
  // the _ character represents one character only.
  string whereClause = featureSource.DisplayColumnName + " like 'e%'";

  // Creates a instance of a query filter. Query filter uses the dragged map rectangle and
  // it will search for all features in layer index = 0, that are contained in this geometry.
  QueryFilter queryFilter = new QueryFilter(whereClause);

  Geometry geometry = null;

  // Querying the feature layer
  using (FeatureDataReader reader = featureSource.GetDataReader(queryFilter, null))
  {
    // Moves the cursor to the next record
    while (reader.Read())
    {
      // Retrieves the feature’s geometry
      geometry = reader.GetGeometry();

      if (geometry != null)
        // If geometry is valid, the map will rendered once for 100 milliseconds.
        map1.FlashGeometry(Pens.Red, (SolidBrush)Brushes.Yellow, 150, 100, 100, geometry);
    }
  }
}

1/7/2015