ArcGIS Pro 2.8 API Reference Guide
Search Method (Table)
Example 

ArcGIS.Core.Data Namespace > Table Class : Search Method
This argument is optional. If unset or set to null, a default query filter will be used, which will cause all rows to be returned.
If set to true, all the entries in RowCursor will reference the most current row returned by Current. To ensure all the entries in RowCursor remain unique, set useRecyclingCursor to false. The default is true.
Searches and retrieves specific rows in this Table that satisfy the criteria set in the queryFilter. If no query filter is set, all rows will be retrieved. This method must be called on the MCT. Use QueuedTask.Run.
Syntax
Public Function Search( _
   Optional ByVal queryFilter As QueryFilter, _
   Optional ByVal useRecyclingCursor As Boolean _
) As RowCursor

Parameters

queryFilter
This argument is optional. If unset or set to null, a default query filter will be used, which will cause all rows to be returned.
useRecyclingCursor
If set to true, all the entries in RowCursor will reference the most current row returned by Current. To ensure all the entries in RowCursor remain unique, set useRecyclingCursor to false. The default is true.

Return Value

A RowCursor that encapsulates the retrieved rows.
Exceptions
ExceptionDescription
If queryFilter is an instance of SpatialQueryFilter, either both the 'FilterGeometry' and 'SpatialRelationship' properties are set or both are not set. Otherwise, an ArgumentException will be raised.
A geodatabase-related exception has occurred.
Example
/*

   Copyright 2018 Esri

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

   See the License for the specific language governing permissions and
   limitations under the License.

*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ArcGIS.Core;
using ArcGIS.Core.Data;
using ArcGIS.Desktop.Framework.Threading.Tasks;

namespace SDKExamples
{
  /// <summary>
  /// Illustrates how to search from a Table.
  /// </summary>
  /// 
  /// <remarks>
  /// <para>
  /// While it is true classes that are derived from the <see cref="ArcGIS.Core.CoreObjectsBase"/> super class 
  /// consumes native resources (e.g., <see cref="ArcGIS.Core.Data.Geodatabase"/> or <see cref="ArcGIS.Core.Data.FeatureClass"/>), 
  /// you can rest assured that the garbage collector will properly dispose of the unmanaged resources during 
  /// finalization.  However, there are certain workflows that require a <b>deterministic</b> finalization of the 
  /// <see cref="ArcGIS.Core.Data.Geodatabase"/>.  Consider the case of a file geodatabase that needs to be deleted 
  /// on the fly at a particular moment.  Because of the <b>indeterministic</b> nature of garbage collection, we can't
  /// count on the garbage collector to dispose of the Geodatabase object, thereby removing the <b>lock(s)</b> at the  
  /// moment we want. To ensure a deterministic finalization of important native resources such as a 
  /// <see cref="ArcGIS.Core.Data.Geodatabase"/> or <see cref="ArcGIS.Core.Data.FeatureClass"/>, you should declare 
  /// and instantiate said objects in a <b>using</b> statement.  Alternatively, you can achieve the same result by 
  /// putting the object inside a try block and then calling Dispose() in a finally block.
  /// </para>
  /// <para>
  /// In general, you should always call Dispose() on the following types of objects: 
  /// </para>
  /// <para>
  /// - Those that are derived from <see cref="ArcGIS.Core.Data.Datastore"/> (e.g., <see cref="ArcGIS.Core.Data.Geodatabase"/>).
  /// </para>
  /// <para>
  /// - Those that are derived from <see cref="ArcGIS.Core.Data.Dataset"/> (e.g., <see cref="ArcGIS.Core.Data.Table"/>).
  /// </para>
  /// <para>
  /// - <see cref="ArcGIS.Core.Data.RowCursor"/> and <see cref="ArcGIS.Core.Data.RowBuffer"/>.
  /// </para>
  /// <para>
  /// - <see cref="ArcGIS.Core.Data.Row"/> and <see cref="ArcGIS.Core.Data.Feature"/>.
  /// </para>
  /// <para>
  /// - <see cref="ArcGIS.Core.Data.Selection"/>.
  /// </para>
  /// <para>
  /// - <see cref="ArcGIS.Core.Data.VersionManager"/> and <see cref="ArcGIS.Core.Data.Version"/>.
  /// </para>
  /// </remarks> 
  public class TableSearch
  {
    /// <summary>
    /// In order to illustrate that Geodatabase calls have to be made on the MCT
    /// </summary>
    /// <returns></returns>
    public async Task TableSearchAsync()
    {
      await QueuedTask.Run(() => MainMethodCode());
    }

    public void MainMethodCode()
    {
      using (Geodatabase geodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(@"C:\Data\LocalGovernment.gdb"))))
      using (Table table             = OpenTable(geodatabase, "EmployeeInfo"))
      {
        // If you are not sure if EmployeeInfo Exists...
        if (table == null)
          return;

        // If you want to make sure the field Name exists...
        TableDefinition tableDefinition = table.GetDefinition();
        if (tableDefinition.FindField("COSTCTRN") < 0)
          //This could be a custom exception...
          throw new Exception("The desired Field Name does not exist. Need to investigate why this is missing");

        // ******************** WITHOUT USING RECYCLING ********************

        List<Row> informationTechnologyEmployees = null;
        List<Row> nullList                       = null;
        List<Row> possiblyEmptyListOfRows        = null;
        List<Row> partiallyPopulatedRows         = null;
        List<Row> distinctCombinationRows        = null;
        List<Row> orderedRows                    = null;

        try
        {
          // This should return a list of rows if the Field Name exists.
          informationTechnologyEmployees = GetRowListFor(table, new QueryFilter {
            WhereClause = "COSTCTRN = 'Information Technology'"
          });

          // This should return a null since EmployeeInfo Table does not have an ADDRESS field.
          nullList = GetRowListFor(table, new QueryFilter {
            WhereClause = "ADDRESS = 'Something'"
          });

          // This should return an empty list Since there is a mismatch in the case of the requested CostCenter Name and the actual.
          possiblyEmptyListOfRows = GetRowListFor(table, new QueryFilter {
            WhereClause = "COSTCTRN = 'Water'"
          });

          // This should return a list of Rows with only OBJECTID, KNOWNAS and EMAIL fields populated. Everything else will be null.  
          partiallyPopulatedRows = GetRowListFor(table, new QueryFilter {
            WhereClause = "COSTCTRN = 'Information Technology'",
            SubFields   = "KNOWNAS, EMAIL"
          });

          Row anyRow = partiallyPopulatedRows.First();
          // Keep in mind that the FindField method is provided as a convenience method. It is a costly operation where 
          // all the fields are enumerated to find the index. So, you might want to be judicious in using it.
          int knownAsFieldIndex = anyRow.FindField("KNOWNAS");
          int emailFieldIndex   = anyRow.FindField("EMAIL");

          foreach (Row partiallyPopulatedRow in partiallyPopulatedRows)
          {
            //do something with
            object knownAsValue = partiallyPopulatedRow[knownAsFieldIndex];
            object emailValue   = partiallyPopulatedRow[emailFieldIndex];
          }

          // This should return a list of Rows with name and location of one Elected Official per Wing .
          distinctCombinationRows = GetRowListFor(table, new QueryFilter {
            WhereClause  = "COSTCTRN = 'Elected Officials'",
            SubFields    = "KNOWNAS, LOCATION, WING",
            PrefixClause = "DISTINCT"
          });

          // This should return a list of Rows ordered by the office numbers of the IT employees.
          orderedRows = GetRowListFor(table, new QueryFilter {
            WhereClause   = "COSTCTRN = 'Information Technology'",
            SubFields     = "KNOWNAS, OFFICE, LOCATION",
            PostfixClause = "ORDER BY OFFICE"
          });
        }
        finally
        {
          Dispose(informationTechnologyEmployees);
          Dispose(nullList);
          Dispose(possiblyEmptyListOfRows);
          Dispose(partiallyPopulatedRows);
          Dispose(distinctCombinationRows);
          Dispose(orderedRows);
        }
        
        //************************ USING RECYCLING *****************************

        using (RowCursor rowCursor = table.Search(new QueryFilter
          {
            WhereClause  = "COSTCTRN = 'Elected Officials'",
            SubFields    = "KNOWNAS, LOCATION, WING",
            PrefixClause = "DISTINCT"
          }))
        {
          while (rowCursor.MoveNext())
          {
            // Do something with rowCursor.Current.  Also, remember to Dispose of it when done processing.
          }
        }
        
        // If you use try to assign the rowCursor.Current to Row references...

        using (RowCursor rowCursor = table.Search(new QueryFilter
          {
            WhereClause  = "COSTCTRN = 'Elected Officials'",
            SubFields    = "KNOWNAS, LOCATION, WING",
            PrefixClause = "DISTINCT"
          }))
        {
          List<Row> rows = new List<Row>();
          Row lastRow    = null;

          while (rowCursor.MoveNext())
          {
            rows.Add(rowCursor.Current);
            lastRow = rowCursor.Current;
          }

          // After the loop is done, lastRow will point to the last Row that was returned by the enumeration.  Each row in the rows
          // list will be pointing to the same Row Object as lastRow, which is the last object that was enumerated by the rowCursor
          // enumerator before moving past the last result, i.e. for each row in rows, the condition row == lastRow will be true.
          // Since Row encapsulates unmanaged resources, it is important to remember to call Dispose() on every entry in the list
          // when the list is no longer in use.   Alternatively, do not add the row to the list.  Instead, process each of them 
          // inside the cursor.

          Dispose(rows);
        }
      }
    }

    /// <summary>
    /// Searches a given Table to return the content of the complete row.  Note that this method is not using Recycling
    /// </summary>
    /// <remarks>using ArcGIS.Core.Data expected </remarks>
    /// <note>ReturnValue is typeof List&lt;Row&gt; </note>
    private List<Row> GetRowListFor(Table table, QueryFilter queryFilter)
    {
      List<Row> rows = new List<Row>();

      try
      {
        using (RowCursor rowCursor = table.Search(queryFilter, false))
        {
          while (rowCursor.MoveNext())
          {
            rows.Add(rowCursor.Current);
          }
        }
      }
      catch (GeodatabaseFieldException fieldException)
      {
        // One of the fields in the where clause might not exist. There are multiple ways this can be handled:
        // 1. You could rethrow the exception to bubble up to the caller after some debug or info logging 
        // 2. You could return null to signify that something went wrong. The logs added before return could tell you what went wrong.
        // 3. You could return empty list of rows. This might not be advisable because if there was no exception thrown and the
        //    query returned no results, you would also get an empty list of rows. This might cause problems when 
        //    differentiating between a failed Search attempt and a successful search attempt which gave no result.

        // logger.Error(fieldException.Message);
        return null;
      }
      catch (Exception exception)
      {
        // logger.Error(exception.Message);
        return null;
      }

      return rows;
    }

    /// <summary>
    /// Opens a table and returns reference if it exists
    /// </summary>
    private static Table OpenTable(Geodatabase geodatabase, string tableName)
    {
      Table table;
      try
      {
        table = geodatabase.OpenDataset<Table>(tableName);
      }
      catch (GeodatabaseCatalogDatasetException exception)
      {
        // logger.Error(exception.Message);
        return null;
      }
      return table;
    }

    private static void Dispose<T>(IEnumerable<T> iterator) where T : CoreObjectsBase
    {
      if (iterator != null)
      {
        foreach (T coreObject in iterator)
        {
          if (coreObject != null)
            coreObject.Dispose();
        }
      }
    }
  }
}
/*

   Copyright 2018 Esri

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

   See the License for the specific language governing permissions and
   limitations under the License.

*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ArcGIS.Core;
using ArcGIS.Core.Data;
using ArcGIS.Core.Geometry;
using ArcGIS.Desktop.Framework.Threading.Tasks;

namespace SDKExamples.GeodatabaseSDK
{
  /// <summary>
  /// Illustrates how to search from a FeatureClass.
  /// </summary>
  /// 
  /// <remarks>
  /// <para>
  /// While it is true classes that are derived from the <see cref="ArcGIS.Core.CoreObjectsBase"/> super class 
  /// consumes native resources (e.g., <see cref="ArcGIS.Core.Data.Geodatabase"/> or <see cref="ArcGIS.Core.Data.FeatureClass"/>), 
  /// you can rest assured that the garbage collector will properly dispose of the unmanaged resources during 
  /// finalization.  However, there are certain workflows that require a <b>deterministic</b> finalization of the 
  /// <see cref="ArcGIS.Core.Data.Geodatabase"/>.  Consider the case of a file geodatabase that needs to be deleted 
  /// on the fly at a particular moment.  Because of the <b>indeterministic</b> nature of garbage collection, we can't
  /// count on the garbage collector to dispose of the Geodatabase object, thereby removing the <b>lock(s)</b> at the  
  /// moment we want. To ensure a deterministic finalization of important native resources such as a 
  /// <see cref="ArcGIS.Core.Data.Geodatabase"/> or <see cref="ArcGIS.Core.Data.FeatureClass"/>, you should declare 
  /// and instantiate said objects in a <b>using</b> statement.  Alternatively, you can achieve the same result by 
  /// putting the object inside a try block and then calling Dispose() in a finally block.
  /// </para>
  /// <para>
  /// In general, you should always call Dispose() on the following types of objects: 
  /// </para>
  /// <para>
  /// - Those that are derived from <see cref="ArcGIS.Core.Data.Datastore"/> (e.g., <see cref="ArcGIS.Core.Data.Geodatabase"/>).
  /// </para>
  /// <para>
  /// - Those that are derived from <see cref="ArcGIS.Core.Data.Dataset"/> (e.g., <see cref="ArcGIS.Core.Data.Table"/>).
  /// </para>
  /// <para>
  /// - <see cref="ArcGIS.Core.Data.RowCursor"/> and <see cref="ArcGIS.Core.Data.RowBuffer"/>.
  /// </para>
  /// <para>
  /// - <see cref="ArcGIS.Core.Data.Row"/> and <see cref="ArcGIS.Core.Data.Feature"/>.
  /// </para>
  /// <para>
  /// - <see cref="ArcGIS.Core.Data.Selection"/>.
  /// </para>
  /// <para>
  /// - <see cref="ArcGIS.Core.Data.VersionManager"/> and <see cref="ArcGIS.Core.Data.Version"/>.
  /// </para>
  /// </remarks> 
  public class FeatureClassSearch
  {
    /// <summary>
    /// In order to illustrate that Geodatabase calls have to be made on the MCT
    /// </summary>
    /// <returns></returns>
    public async Task FeatureClassSearchAsync()
    {
      await QueuedTask.Run(() => MainMethodCode());
    }

    public void MainMethodCode()
    {
      using (Geodatabase fileGeodatabase = new Geodatabase(new FileGeodatabaseConnectionPath(new Uri(@"C:\Data\LocalGovernment.gdb"))))
      using (FeatureClass featureClass   = fileGeodatabase.OpenDataset<FeatureClass>("PollingPlace"))
      {
        FeatureClassDefinition featureClassDefinition = featureClass.GetDefinition();

        int areaFieldIndex = featureClassDefinition.FindField(featureClassDefinition.GetAreaField());

        // ******************** WITHOUT USING RECYCLING ********************

        QueryFilter queryFilter = new QueryFilter { WhereClause = "CITY = 'Plainfield'" };

        List<Feature> features = new List<Feature>();

        // Searching is similar to that of Table when using Queryfilter.
        using (RowCursor cursor = featureClass.Search(queryFilter, false))
        {
          while (cursor.MoveNext())
          {
            // Each object returned by RowCursor.Current can be cast to a Feature object if the Search was performed on a FeatureClass.
            features.Add(cursor.Current as Feature);
          }
        }
        
        IEnumerable<Feature> featuresHavingShapePopulated = features.Where(feature => !feature.GetShape().IsEmpty);

        // Since Feature encapsulates unmanaged resources, it is important to remember to call Dispose() on every entry in the list when
        // the list is no longer in use.  Alternatively, do not add the features to the list.  Instead, process each of them inside the cursor.

        Dispose(features);

        // ******************** USING RECYCLING ********************

        using (RowCursor recyclingCursor = featureClass.Search(queryFilter))
        {
          while (recyclingCursor.MoveNext())
          {
            // Similar to a RowCursor on a Table, when a MoveNext is executed, the same feature object is populated with the next feature's details
            // So any processing should be done on the Current Feature before the MoveNext is called again.

            Feature feature = (Feature)recyclingCursor.Current;

            if (Convert.ToDouble(feature[areaFieldIndex]) > 500)
              Console.WriteLine(feature.GetShape().ToXML());
          }
        } 
      }
      
      // Opening a Non-Versioned SQL Server instance.

      DatabaseConnectionProperties connectionProperties = new DatabaseConnectionProperties(EnterpriseDatabaseType.SQLServer)
      {
        AuthenticationMode = AuthenticationMode.DBMS,

        // Where testMachine is the machine where the instance is running and testInstance is the name of the SqlServer instance.
        Instance = @"testMachine\testInstance",

        // Provided that a database called LocalGovernment has been created on the testInstance and geodatabase has been enabled on the database.
        Database = "LocalGovernment",

        // Provided that a login called gdb has been created and corresponding schema has been created with the required permissions.
        User     = "gdb",
        Password = "password",
        Version  = "dbo.DEFAULT"
      };
      
      using (Geodatabase geodatabase                 = new Geodatabase(connectionProperties))
      using (FeatureClass schoolBoundaryFeatureClass = geodatabase.OpenDataset<FeatureClass>("LocalGovernment.GDB.SchoolBoundary"))
      {
        // Using a spatial query filter to find all features which have a certain district name and lying within a given Polygon.
        SpatialQueryFilter spatialQueryFilter = new SpatialQueryFilter
        {
          WhereClause    = "DISTRCTNAME = 'Indian Prairie School District 204'",
          FilterGeometry = new PolygonBuilder(new List<Coordinate2D>
          {
            new Coordinate2D(1021880, 1867396),
            new Coordinate2D(1028223, 1870705),
            new Coordinate2D(1031165, 1866844),
            new Coordinate2D(1025373, 1860501),
            new Coordinate2D(1021788, 1863810)
          }).ToGeometry(),

          SpatialRelationship = SpatialRelationship.Within
        };
        
        using (RowCursor indianPrairieCursor = schoolBoundaryFeatureClass.Search(spatialQueryFilter, false))
        {
          while (indianPrairieCursor.MoveNext())
          {
            using (Feature feature = (Feature)indianPrairieCursor.Current)
            {
              // Process the feature.
              Console.WriteLine(feature.GetObjectID());
            }
          }
        }
      }
    }

    private static void Dispose<T>(IEnumerable<T> iterator) where T : CoreObjectsBase
    {
      if (iterator != null)
      {
        foreach (T coreObject in iterator)
        {
          if (coreObject != null)
            coreObject.Dispose();
        }
      }
    }
  }
}
Requirements

Target Platforms: Windows 10, Windows 8.1

See Also

Reference

Table Class
Table Members