Geodatabase


Supported with:
Library dependencies: System, SystemUI, Geometry, Display, Server, Output

Additional library information: Contents, Object Model Diagram

The Geodatabase library provides the application programming interface (API) for the geodatabase. The geodatabase is a repository of geographic data built on standard industry relational and object relational database technology. The objects in the library provide a unified programming model for supported data sources in ArcGIS. The Geodatabase library defines many of the interfaces implemented by data source providers higher in the architecture.
The geodatabase can be extended by developers to support specialized types of data objects, such as features, classes, and so on. In addition, it can have custom vector data sources added using the plug-in data source objects. The native data types supported by the geodatabase cannot be extended.

See the following sections for more information about this namespace:

Core geodatabase

The following illustration is a simplified view of the objects in the core geodatabase model:
The following summarizes the core geodatabase model shown in the preceding illustration:

Workspaces

A workspace is a container of spatial and nonspatial datasets, such as feature classes, raster datasets, and tables. Workspaces provide methods to instantiate existing datasets and to create new datasets. See the following illustration showing Workspace objects:
Workspaces are classified into the following types specified by the esriWorkspaceType enumerator—esriFileSystemWorkspace, esriLocalDatabaseWorkspace, and esriRemoteDatabaseWorkspace:
Other workspace types include the following:
A WorkspaceFactory is a dispenser of workspaces and allows a client to connect to a workspace specified by a set of connection properties. A workspace represents a database or a data source that contains one or more datasets. Examples of datasets include tables, feature classes, and relationship classes. See the following illustration showing WorkspaceFactory objects:
A WorkspaceFactory is a cocreatable, singleton object. A WorkspaceFactory maintains a pool of connected and active workspaces referenced by the application. Connection properties are specified using a PropertySet object and can be saved to a connection file.
A WorkspaceFactory also supports methods used to browse and manage file system workspaces and methods to manage connection files for remote database workspaces.
The following code example connects to an ArcSDE for Oracle geodatabase:
[Java]
SdeWorkspaceFactory sdeWorkspaceFactory = new SdeWorkspaceFactory();
PropertySet pset = new PropertySet();
pset.setProperty("SERVER", "zinc");
pset.setProperty("INSTANCE", "9192");
pset.setProperty("USER", "gdb");
pset.setProperty("PASSWORD", "gdb");
pset.setProperty("VERSION", "sde.DEFAULT");
Workspace featureWksp = new Workspace(sdeWorkspaceFactory.open(pset, 0));

IFeatureWorkspace

Use the IFeatureWorkspace interface to access and manage datasets that are a key component of a feature based geodatabase (Tables and ObjectClasses, FeatureClasses, FeatureDatasets, and RelationshipClasses).
All of the open methods, such as OpenTable, take a dataset name as input. When working with an ArcSDE geodatabase, the name can be fully qualified—for example, database.owner.tablename or owner.tablename—using the qualification character appropriate to the underlying database. If the input name is not fully qualified, it is qualified using the connected user for the workspace.
When working with geodatabases (personal, file, or ArcSDE), the workspace keeps a running object table of instantiated datasets. Multiple calls to open an already instantiated dataset returns a reference to the instantiated dataset.
The OpenTable method can be used to open any existing table or object class in the workspace given its fully qualified name. The returned table object will always support the ITable interface. The returned table object will support additional interfaces depending on the type of table—for example, ObjectClasses will additionally support the IObjectClass interface.
The OpenFeatureClass method can be used to open an existing feature class in the workspace given its fully qualified name.
Every feature class in a geodatabase has a unique fully qualified name and the OpenFeatureClass method can be used to open feature classes that are part of a feature dataset.
The following code example opens a shapefile as a feature class:
[Java]
static void openShapeFile()throws Exception{
    ShapefileWorkspaceFactory shapefileWorkspaceFactory = new
        ShapefileWorkspaceFactory();
    Workspace featureWksp = new Workspace(shapefileWorkspaceFactory.openFromFile(
        "c:/Data/usa", 0));
    FeatureClass fclass = new FeatureClass(featureWksp.openFeatureClass("states.shp")
        );
    System.out.println("There are" + fclass.featureCount(null) + " states");
}

ISQLSyntax

Applications can use the ISQLSyntax interface to help construct SQL queries and where clauses that are database system independent. See the following illustration showing ISQLSyntax:
GetSpecialCharacter can be used to return the DBMS dependent character that represents a SQL special character, including the following:
Use the the ParseTableName and ParseColumnName methods in applications to split the fully qualified name for a dataset or for a column in a table into its components (database, owner, table, and column).
Applications that you want to be RDBMS independent should not assume a period (.) is the delimiter used to separate the components of a fully qualified dataset name. The IDataset.GetName method for a dataset in a geodatabase and the IDatasetName.GetName property for a dataset name object returns the fully qualified name for the dataset (the name object for the dataset, obtained using the IDataset.GetFullName property).
Use the QualifyTableName and QualifyColumnName methods in applications to construct fully qualified dataset and column names.

Editing data

Applications can use specified transactions to manage direct updates, for example, any feature classe tagged as not requiring an edit session can be updated outside of an edit session. When using transactions to manage direct updates, applications are responsible for discarding any cached row objects at transaction boundaries.
ITransactions is an optional interface that allows an application to explicitly control database transactions. The interface does not support nested transactions.
Applications should not use transactions when performing updates in an edit session. In the context of an edit session, transactions are managed by the workspace and automatically started and stopped as needed.
Applications should be aware that data definition language (DDL) operations made through the ArcObjects geodatabase data access objects (for example, deleting a feature dataset or creating a new feature class) use database transactions to ensure integrity of the data dictionary tables and commit the transaction at the end of the operation. Applications should not invoke DDL operations in an application transaction—restrict application transactions to data manipulation language (DML) operations, such as data updates.
Applications can use geodatabase edit sessions to manage database transactions. It is possible to start an edit session in one of two modes. The IWorkspaceEdit interface allows the application to start and stop edit sessions in the versioned edit session mode only.
A versioned edit session begans by using the StartEditing method. The WithUndoRedo parameter can be used to suppress undo and redo logging if the workspace supports such suppression. Shapefiles support suppression of undo and redo logging, but ArcSDE does not.
The IMultiuserWorkspaceEdit interface also allows the application to start and stop edit sessions during the update of objects in a geodatabase. This differs from the IWorkspaceEdit interface in that the IMultiuserWorkspaceEdit interface is only supported by workspaces that support both edit session modes, namely ArcSDE geodatabases. It is recommended that the IMultiuserWorkspaceEdit interface be used if it is the intent to control the edit session mode used when editing. By default, through the StartEditing method, an edit session will be started in the versioned edit session mode.Therefore, it is necessary to use the IWorkspaceEdit interface to edit local workspaces.
If the IMultiuserWorkspaceEdit interface is used, the edit session can be started in versioned or nonversioned edit session modes. If the edit session mode is set to versioned, the only changes to data that an application sees in an edit session are changes that are made by that application.
Changes made by other concurrently executing applications (if allowed) are not seen until the edit session is saved or discarded. On the other hand, editing in an edit session in nonversioned mode is the equivalent of performing standard database transactions. You still perform the edits in a standard edit session; however, when you finish, the changes are committed as a single transaction by saving. If you don't want to commit the changes, abort the edit session without saving. Each transaction can include as few or as many operations as required, provided they fall within a single edit session.
Editing in a nonversioned edit session mode alters the data source and does not store the changes in delta tables like versioned editing. This avoids the overhead of managing these extra tables and allows you to adapt nonESRI applications so they can read and edit the data. However, since you edit the data source, you cannot undo or redo an individual edit if you make a mistake. The only way to undo edits is to undo all edits by quitting the edit session without saving. You can perform nonversioned edits on simple data only—points, lines, polygons, annotation, and relationships. You cannot perform nonversioned edits on complex data, such as feature classes in a topology or geometric network.
If undo and redo facilities are required when editing in a versioned edit session mode, all related changes to objects in the database in an edit session should be grouped into edit operations (use the StartEditOperation method to start an edit operation).
Applications are responsible for calling the AbortEditOperation method to stop an edit operation if errors are detected in the methods executed for an edit operation.
Applications are responsible for calling StopEditOperation to mark the end of a successfully completed edit operation. Completed edit operations can be thought of as being pushed onto an undo stack.
The UndoEditOperation can be used to roll the state of the edit session back to what it was prior to the execution of the edit operation at the top of the undo stack. Undoing an edit operation pops the edit operation from the undo stack and adds it to a redo stack.
The RedoEditOperation rolls the state of the edit session forward to what it was after the execution of the edit operation at the top of the redo stack, pops the redone edit operation from the redo stack, and pushes it back onto the undo stack. Performing a new edit operation clears the redo stack.
The StopEditing method is used to end an edit session. The SaveEdits parameter controls whether or not edits are saved or discarded. A multiversioned database can support multiple concurrent edit sessions on the same version of the database. In such a scenario, StopEditing returns an error code of FDO_E_VERSION_REDEFINED if it detects the database state associated with the version being edited is not the same as it was at the beginning of the edit session (indicating that the version was modified by some other edit session). In this case, the application is responsible for calling the IVersionEdit.Reconcile method to reconcile the edit session against the current state of the version being edited. StopEditing may be called again after reconciliation.
The geodatabase guarantees unique instancing of row objects retrieved from the database in an edit session. Any data access call that retrieves a nonrecycling object with a particular object ID returns the in-memory instance of the object if the object has already been instantiated by the application. Such behavior is needed to ensure application correctness when updating complex object models—for example, models with relationship based messaging or models with network features where updates to the geometry of a feature affect the geometry of topologically related features.
The following code example shows a simple nonversioned edit session on an ArcSDE workspace. If the user chooses to undo the edit operation, there will be no outstanding edits; therefore, the prompt to save the work will not appear. For this reason, do all object editing in an edit session. The geodatabase data access APIs, such as IRow.Store, ITable.Update, and ITable.Insert, fail if you attempt to use them outside of an edit session on object and feature classes that are marked as requiring an edit session to ensure unique instancing semantics. Use IObjectClassInfo2.CanBypassEditSession to determine the situation.
[Java]
static void sdeWorkspaceEdit()throws Exception{
    SdeWorkspaceFactory sdeWorkspaceFactory = new SdeWorkspaceFactory();
    PropertySet pset = new PropertySet();
    pset.setProperty("SERVER", "pine");
    pset.setProperty("INSTANCE", "9192");
    pset.setProperty("USER", "gdb");
    pset.setProperty("PASSWORD", "gdb");
    pset.setProperty("VERSION", "sde.DEFAULT");
    Workspace featureWksp = new Workspace(sdeWorkspaceFactory.open(pset, 0));
    FeatureClass fclass = new FeatureClass(featureWksp.openFeatureClass(
        "VTEST.States"));
    IMultiuserWorkspaceEdit pMWorkspaceEdit = new IMultiuserWorkspaceEditProxy
        (featureWksp);
    if (pMWorkspaceEdit.supportsMultiuserEditSessionMode
        (esriMultiuserEditSessionMode.esriMESMNonVersioned)){
        pMWorkspaceEdit.startMultiuserEditing
            (esriMultiuserEditSessionMode.esriMESMNonVersioned);
        Feature feature = (Feature)fclass.getFeature(1);
        feature.delete();
        boolean[] bHasEdits = new boolean[1];
        featureWksp.hasEdits(bHasEdits);
        if (bHasEdits[0]){
            featureWksp.stopEditing(true);
        }
    }
}

Rules for object editing

The following summarizes the rules for correct object editing on a geodatabase:

Workspace extensions

A workspace representing a geodatabase can have one or more workspace extensions. A workspace extension extends the functionality of a workspace, for example, by managing a new type of custom dataset or by maintaining custom data dictionary information on datasets. A workspace extension is usually used in conjunction with an application or editor extension that acts as the client of the workspace extension.
The workspace instantiates all WorkspaceExtensions that are registered in the component category CATID_GeodatabaseWorkspaceExtensions at connect time. An application extension can find a workspace extension by its well known globally unique identifier (GUID) and invoke methods supported by the extension as appropriate. It will also instantiate all workspace extensions registered with a workspace using IWorkspaceExtensionManager.RegisterExtension.
IWorkspaceExtension is a mandatory interface that must be supported by all workspace extensions. The GUID property returns the well known GUID for the extension and is guaranteed to be unique. The Name property is the name of the extension. The GetPrivateDatasetNames and GetDataDictionaryNames properties return the names of tables and datasets that are private to the extension and will not be exposed to browsing clients by the workspace.

Datasets

A dataset is an abstract class that represents a named collection of data in a workspace (datasets can contain other datasets). All datasets support the IDataset interface and can optionally support other interfaces, including IDatasetEdit, ISchemaLock, and IMetadata. Datasets can include tables, feature classes, relationship classes, feature datasets, topologies, and geometric networks. See the following illustration showing Dataset objects:
Datasets appear as items in the ArcCatalog tree view under their workspace. See the following illustration showing datasets in the ArcCatalog tree view:
Feature datasets are collections of feature classes and can also contain relationship classes, geometric networks, or topologies. Feature classes that store simple features can be organized inside or outside a feature dataset. Those outside a feature dataset are called stand-alone feature classes. Feature classes that store topological features, for example, those participating in geometric networks or topologies, must be contained in a feature dataset to ensure a common spatial reference. A feature dataset exists only in a geodatabase workspace; all the datasets contained in the feature dataset are also part of the same geodatabase.
When programming with feature classes, remember that the feature class may or may not belong to a feature dataset.
The following code example to get the workspace for a feature class assumes a feature dataset exists and therefore, may fail:
[Java]
FeatureClass fclass = new FeatureClass(featureWksp.openFeatureClass("LOBUSER.States")
    );
FeatureDataset dataset = new FeatureDataset(fclass.getFeatureDataset());
Workspace workspace = new Workspace(dataset.getWorkspace());
The following code example works for stand-alone feature classes and those in feature datasets:
[Java]
workspace = new Workspace(fclass.getWorkspace());
Each dataset in a geodatabase must have a unique name. In particular, each feature class in a geodatabase must have a unique name independent of the feature dataset that it contains. This is different from a file system model where two folders can contain files with the same local name in the folder.

Table, object class, and feature class

A Table object has one or more columns, referred to as fields, and contains an unordered collection of rows. For each field, each row has exactly one value in the data type of the field.
A table is a dataset. Properties, such as the name of the table, the persistable name object for the table, and the workspace containing the table can be obtained via the IDataset interface. See the following illustration showing Table, ObjectClass, and FeatureClass objects:
In relational terms, a Table object represents a RDBMS table or view. In objected oriented terms, a Table object represents an ObjectClass or a RelationshipClass in a geodatabase. A Table object hands out Row objects that support application callable methods, depending on the type of data stored in the table. The Name property of a table, accessible via the IDataset interface, returns its fully qualified name. See the following illustration showing Dataset and Table objects:
The level of qualification can vary depending on the host database management system (DBMS). For example, a table (pipes) owned by a user (gas) may be called pipes in Microsoft Access, gas.pipes in Oracle, and mydb.gas.pipes in SQL Server. The ParseTableName method on the ISQLSyntax interface supported by the table's workspace can be used to split the fully qualified name into its components.
An object class is a table whose rows represent entities modeled as objects with properties and behavior. The Row objects handed out by an object class support the IRow and the IObject interfaces. See the following illustration showing Dataset, Table, and ObjectClass objects:
 
An object class can participate in any number of relationship classes that relate its instances to objects (entities) in other object classes. An object class can contain a discriminating field (subtype field), that can be used to partition its instances into a number of subtypes. All subtypes share the same field definition and are stored in the same table; however, individual subtypes can differ in the default values and domains assigned to fields. The subtyping mechanism can also be used in defining attribute, connectivity, and topology rules that apply to the instances of the object class. The subtyping mechanism is a lightweight alternative to creating multiple subclasses, and each is represented by its own object class.
An object class has a non-negative object class ID that is unique in the geodatabase. This ID is assigned to the object class when it is created or when an existing table in the RDBMS is registered with the geodatabase as an object class. The name of the object class is the same as the name of the table in the DBMS in which the objects in the object class are stored and follows the same fully qualified naming conventions.
An object class can have a GetAliasName property that is stored as part of its definition by the geodatabase. The GetAliasName can be retrieved and used for display purposes by applications. See the following illustration showing IObjectClass:
An object class may have a ModelName property that is stored as part of its definition by the geodatabase. The model name is not exposed to end users and if defined, can be used as a search key to find an object class by a standard model name that is adhered to across databases. A model name must be unique across the workspace.
Although all objects in a feature class or object class must have the same behavior and attributes, not all objects have to share the same default values and validation rules. You can group features and objects into subtypes. Subtypes differentiate objects based on their rules.
A FeatureClass is an ObjectClass whose objects are features, that is, a feature class is a collection of spatial entities, modeled as objects with properties and behavior. All of the features in a feature class share the same attribute schema (have the same set of named fields). The row objects handed out by a feature class support the IRow, IObject, and IFeature interfaces. See the following illustration showing the Dataset, Table, ObjectClass, and FeatureClass objects.
A feature class has one distinguished shape field (type Geometry). The shape field stores the geometry (shape property) for the features in the feature class.
The following code example uses the Workspace object to return a FeatureClass object:
[Java]
AccessWorkspaceFactory accessWorkspaceFactory = new AccessWorkspaceFactory();
Workspace featureWksp = new Workspace(accessWorkspaceFactory.openFromFile(
    "c:/Data/usa/usa.mdb", 0));
FeatureClass fclass = new FeatureClass(featureWksp.openFeatureClass("states"));

Rows, objects, and features

A RowBuffer is a transient object capable of holding the state of a row but has no object identity. It is used primarily during data loading as the argument to the InsertRow method on an insert cursor. A Row-Buffer is obtained from a table using the CreateRowBuffer method.
The IRowBuffer interface contains methods to access the state (the set of field values) for a row buffer. These methods take as an argument the numeric index of the field to be accessed. A Row object is an instantiated software object that represents a persistent row in a table. A Row object is normally obtained from a cursor on a table (for example, ICursor.NextRow) or fetched directly given its object ID (for example, ITable.GetRow). See the following illustration showing RowBuffer and Row objects:
Once retrieved, clients can query the Row object for additional interfaces and invoke methods on the Row object. The class identifier (CLSID) property of a table determines the type of Row object returned by the table. A new persistent Row object is created using the ITable.CreateRow method. The act of creating the row assigns it identity.
Use the CreateRow method to create new persistent Row objects, as opposed to directly cocreating the Row objects. The latter will not create a row in the underlying persistent store.
A row has a set of fields. The set of fields for a row is the same as the set of fields for its table. In particular, the numeric index of a field in the Fields collection of its table is the same as the numeric index of the field in the Fields collection of the row, which is the same as the numeric index used to access the value of the field from the row. This means that application programs can and should cache field numeric indexes using the FindField method on the Table object, rather than invoking the FindField method once per row returned by a cursor.
The following code example shows the creation of a row and an update, followed by the deletion of the row:
[Java]
Table table = new Table(wksp.openTable("STATES"));
int i = table.findField("STATE_NAME");
wksp.startEditing(false);
wksp.startEditOperation();
Row row = new Row(table.createRow());
br > row.setValue(i, "Exploits");
row.store();
row.setValue(i, "Badger");
row.store();
row.delete();
wksp.stopEditOperation();
wksp.stopEditing(false);
An ObjectClass is a table whose Row objects represent entities. The Row objects handed out by an ObjectClass support the IRow and IObject interface and are referred to as Object objects or Objects). An alternative name for Object object in this context is Entity object. See the following illustration showing RowBuffer, Row, and Object:
The IObject interface is almost identical to IRow, from which it inherits. The only additional property is a direct link to the object class.
The instances of an ObjectClass can be partitioned into a number of subtypes. The IRowSubtypes interface on an object contains methods that allow determination and modification of the subtype to which an object belongs and allow initialization or resetting of the field values of an object to the default values defined for its subtype.
When objects are programmatically created via the CreateRow method on the ITable interface (or for features with the CreateFeature method on the IFeatureClass interface), the default subtype is not automatically set, nor are the default values initialized. When using ArcMap, these tasks are automatically performed. However, if you are programmatically creating an object (or feature) that has default values, the following code example indicates the proper sequence that should be followed:
[Java]
FeatureClass fclass = new FeatureClass(wksp.openFeatureClass("GDB.STATES"));
wksp.startEditing(false);
wksp.startEditOperation();
Feature feature = (Feature)fclass.createFeature();
wksp.stopEditOperation();
wksp.stopEditing(false);
// Get the default subtype code for the feature class.
int defaultSubtype = fclass.getDefaultSubtypeCode();
//Set the subtype and initialize the default values for the feature.
feature.setSubtypeCode(defaultSubtype);
feature.initDefaultValues();
A feature is a spatial object and is a member of a feature class, being a row in the feature class table. A feature has an associated shape, the type of which is defined by the feature class. The shape objects are point, multipoint, multipatch, polyline, and polygon—objects in the Geometry object model. See the following illustration showing RowBuffer, Row, Object, and Feature objects:
Mostly you will deal with simple features, but there are various special kinds defined by the esriFeatureType enumeration—includes annotation, dimension, raster catalog, and various network features.
The IFeature interface extends IObject and IRow, from which it inherits. The additional facilities deal with the shape of the feature. Use the GetShape and SetShapeByRef property to get or set the shape. This can be more convenient than the alternative of using the GetValue property since you don't have to work out the index of the shape field.
At 9.3, the GeometryServer class was added to the Geodatabase library. The GeometryServer lets clients programmatically apply common geometric operations to arrays of geometry objects. Buffering, projection of geometries from one spatial reference system to another, and evaluation of spatial relations are some of the operations provided. For more information, see the IGeometryServer interface (located in the Geometry library) as well as the Geometry library overview.

Query, cursors, and selection

The following illustration shows Query, Cursor, and Selection objects:
 

Cursors

A cursor is a data access object that can be used to iterate over the set of rows in a table, or query or insert new rows into a table. There are three forms of Cursor objects—Search, Insert, and Update cursors. Each of these types of cursors is returned by the corresponding Search, Insert, or Update method on a Table or FeatureClass object. The Search and Update methods take a QueryFilter as input, which can be used to restrict the set of rows returned.
A Search cursor can be used to retrieve rows specified by a query filter and supports a NextRow method. An Update cursor can be used to positionally update and delete rows specified by a query filter and supports the NextRow, UpdateRow, and DeleteRow method.
An Insert cursor is used to insert rows into a table and supports the InsertRow method. All of these methods are available in the ICursor interface—make the calls appropriate to the type of cursor. See the following illustration:
The NextRow method on a Search or Update cursor returns the next row in the result set to the application. The returned Row object is allocated and hydrated by the cursor and a reference to it is handed to the application. To retrieve all rows in a result set containing N rows, the application must make N calls to NextRow.
Cursors are forward only and do not support backing up and retrieving rows that have already been retrieved or making multiple passes over data. If an application needs to make multiple passes over the data, the application needs to re-execute the query that returned the cursor. If both executions of the query are made in the same edit session (or database transaction with the appropriate level of isolation), the application is guaranteed not to see any changes made to the data by other concurrently executing applications.
The following code example shows a simple cursor operation and prints the value of the first field for each row in a table:
[Java]
Cursor cursor = new Cursor(table.ITable_search(null, false));
IRow row = cursor.nextRow();
while (row != null){
    System.out.println(row.getValue(0));
    row = cursor.nextRow();
}
No data is fetched from the database until the NextRow method is called.
A cursor has a recycling property that controls how it allocates Row objects. Recycling cursors allocates a single Row object and rehydrates it on each fetch. They can be used to optimize read-only access, for example, when drawing. It is illegal to maintain a reference on a Row object returned by a recycling cursor across multiple calls to NextRow on the cursor.
 
Do not modify Row objects returned by a recycling cursor. Nonrecycling cursors return a separate Row object on each fetch. The objects returned by a nonrecycling cursor can be modified (setting the IRow.Value property or any custom ancestor supported by the Row object) and stored with polymorphic behavior. The geodatabase guarantees unique instance semantics on nonrecycling Row objects fetched during an edit session. If the Row object to be retrieved by a call to NextRow has already been instantiated in the calling application, a reference to the existing Row object will be returned.
All Row objects retrieved from a table using a cursor logically contain the same ordered set of fields—this set is the same as the ordered set of fields for the cursor and the table. In particular, the numeric index of a field in the Fields collection of the table is the same as the numeric index of the field in the Fields collection of the cursor, which is the same as the numeric index of the field for the row. Therefore, the FindField method needs to be used only once per table or cursor. If the query filter used in generating a cursor does not include certain fields, the resulting row objects will still logically contain these fields; however, they will not have hydrated values for these fields. If an application accesses these field values for the row, a variant of type empty (VT_EMPTY) will be returned. This value is different from the Null value (VT_NULL) that is returned when the value of a fetched field is null.
Use the UpdateRow method to update the row at the current position of an update cursor (making a call to NextRow on a cursor returns a row and positions the cursor on that row). After fetching a Row object using NextRow, the application can modify the row as needed and call UpdateRow, passing in the modified row. This is an alternative to calling store on the retrieved row. Using a recycling update cursor can be faster than calling store on the rows returned by a search cursor when performing direct updates outside an edit session on simple data. If the row objects for the table are not simple (don't have custom behavior or participate in composite relationships or relationships with notification), calling UpdateRow on the cursor generates a call to store on the Row object to trigger the custom behavior (there will be no performance gain).
The DeleteRow method can be used to delete the row at the current position of an Update cursor (that is, to delete the row returned by the last call to NextRow on this cursor). After fetching the Row object using NextRow, the application should call DeleteRow on the cursor to delete the row. The application is responsible for discarding the husk deleted Row object. Using a recycling Update cursor to delete rows can be faster then calling delete on the rows returned by a Search cursor when performing direct updates outside an edit session on simple data. If the Row objects for the table are not simple (they don't have custom behavior) or participate in composite relationships or relationships with notification, DeleteRow on the cursor generates a call to delete on the Row object to trigger custom behavior (there will be no performance gain).
Insert cursors are used to bulk insert rows. Using an Insert cursor offers significantly faster performance for data loading into simple tables and feature classes (tables whose CLSID is esriGeoDatabase.Row, esriGeoDatabase.Object, or esriGeoDatabase.Feature) than the alternative—making multiple calls to CreateRow on the table followed by calling store on the created row.
Insert cursors on tables that contain nonsimple objects, such as internally, use the CreateRow and Store methods to achieve polymorphism and there is no difference in performance in these cases. The InsertRow method takes a RowBuffer as an argument.
Applications obtain a RowBuffer using the CreateRowBuffer method on the Table object into which rows are to be inserted. Each call to InsertRow on the cursor creates a new row in the database whose initial values are set to the values in the input row buffer. The object ID for the created row is returned by the InsertRow method.
The UseBuffering method argument to the Insert method on a table returns an Insert cursor that buffers rows on the clients and sends them to the server in batches for increased performance. The application is responsible for calling flush on the Insert cursor after all rows have been inserted. If a call to flush is not made, the cursor flushes its buffers on destruction (when the application releases all references on the cursor). However, relying on the destructor to flush the insert cursor does not give the application the chance to detect errors that can arise on the call to flush (for example, if the tablespace [disk] for the table in the underlying database fills up).
The FeatureCursor object is a type of Cursor object. It performs in the same way, except it is based on a feature class rather than a generic table. See the following illustration showing Cursor and FeatureCursor objects:

IFeatureCursor

The IFeatureCursor interface provides access to a set of features in a feature class. It operates in the same way as ICursor, although it does not inherit from that interface. This saves you from having to use QueryInterface when dealing with features rather than rows. See the following illustration showing the set of features in a feature class:
All the discussion for Cursor objects is appropriate to Feature cursors—there is a direct correspondence between the methods on the various interfaces.

Query filters and spatial filters

A QueryFilter object specifies a filter for tabular data based on attribute values. It is used to restrict the set of rows or the set of columns retrieved from a single table or feature class. The primary use of a query filter is to specify the set of rows to be returned when opening a cursor on a table. It is also used in a number of other cases where a subset of the data in a table needs to be specified.
Some scenarios of using a QueryFilter include opening a cursor on some of the rows in a table, deleting features meeting certain criteria, counting the number of features satisfying a condition, and defining which features will be rendered on the map. See the following illustration showing IQueryFilter:
The following code example shows how to select features for the state of California. This code works on any feature layer with a STATE_NAME attribute—QueryFilters are not specific to any particular dataset.
[Java]
FeatureClass fclass = new FeatureClass(wksp.openFeatureClass("states.shp"));

QueryFilter qfilter = new QueryFilter();
qfilter.setWhereClause("STATE_NAME = 'California'");
There is no need to specify a WhereClause if you want to filter the fields of data. You can also use the Visual Basic (VB) keyword (Nothing) in place of a QueryFilter for those methods that require one, for example, to count the features in a feature class. See the following code example:
[Java]
SelectionSet selection = new SelectionSet(fclass.select(qfilter,
    esriSelectionType.esriSelectionTypeHybrid,
    esriSelectionOption.esriSelectionOptionNormal, wksp));
System.out.println("Number of selected features = " + selection.getCount());
You can use the SubFields property to improve performance when using query filters. The performance gain comes from fetching the required field values rather than all the data for each row. The default value for SubFields is an asterisk (*), which indicates that all field values will be returned. It isn't necessary to set the subfields when the query filter is used in a context in which no attribute values are fetched, for example, when selecting features. A QueryFilter has properties named GetSubFields and GetWhereClause and represents a subset of the single table queries that can be made against a table in a SQL database using the SQL SELECT statement. QueryFilters map to simple SQL Select statements of the form SELECT <field names> FROM <table name> WHERE <where-clause that references only table name>.
The SQL syntax used to specify the SetWhereClause of QueryFilter objects is the same as that of the underlying database holding the data. An application can use the ISqlSyntax interface on a workspace to determine information about the SQL syntax used, such as the delimiter character used in qualifying table and field names and the identifier quote character. This information is available for the different types of workspaces (ArcSDE for Oracle, ArcSDE for SqlServer, Access, shapefile, coverage, and so on). Unlike QueryDef objects, QueryFilter objects are supported across all workspace types, including shapefiles and coverages.
A SpatialFilter is a QueryFilter that includes both spatial and attribute constraints. A SpatialFilter can be used to restrict the set of features retrieved from a feature class using both spatial and attribute restrictions. A spatial filter has a single query geometry that specifies the geometry against which the features in the feature class will be tested. See the following illustration showing QueryFilter and SpatialFilter:
Because ArcObjects supports a number of different geometry types, including both single and multipart geometries and geometry collections, one way of expressing a complex spatial query is by building an appropriate query geometry to pass as input to the spatial filter. A spatial filter has a single geometric shape that is used in the query. You can form more complicated spatial queries by using several spatial filters in succession.
You can use spatial filters everywhere that query filters are used, as long as the dataset to be queried has a spatial field. The following are some example tasks:

ISpatialFilter

Use ISpatialFilter to define a query with geographic criteria—set the following properties: SetGeometryByRef, SetGeometryField, and SetSpatialRel. See the following illustration showing ISpatialFilter:
The GeometryEx method can be used to set the query geometry in the case of large query geometries where the application surrenders ownership of the geometry to the filter. In this case, the filter may modify (project) the query geometry in place if the spatial reference of the query geometry is different from the native spatial reference of the feature class or the requested output spatial reference. The spatial reference in which the features should be returned by the query is specified using the SetOutputSpatialReferenceByRef property in the IQueryFilter interface.
The following code example shows a simple selection of features that intersect a given shape. It assumes an existing feature layer and a valid geometry pointer (perhaps derived from end user input).
[Java]
SpatialFilter sfilter = new SpatialFilter();
IGeometry geometry = null;
sfilter.setGeometryByRef(geometry);
sfilter.setGeometryField(flayer.getFeatureClass().getShapeFieldName());
sfilter.setSpatialRel(esriSpatialRelEnum.esriSpatialRelIntersects);
flayer.selectFeatures(sfilter, esriSelectionResultEnum.esriSelectionResultNew, false)
    ;
ISpatialFilter inherits the members of IQueryFilter—the preceding code example can be extended by setting the WhereClause property on the spatial filter.
The SpatialRel property takes an enumeration that defines the relationship between the query geometry and the target feature geometry; must be satisfied for the target feature to be returned by the query. The supported spatial relationships are the basic Clementini relationships, specified as part of the OpenGIS simple feature access standard. See the following illustration showing the esriSpatialRelEnum enumeration:
The five basic Clementini relationships are disjoint, touches, overlaps, crosses, and within. The following are mapped to the corresponding Clementini relationships—esriSpatialRelIntersects, esriSpatialRelTouches, esriSpatialRelCrosses, esriSpatialRelOverlaps, esriSpatialRelWithin, and esriSpatialRelContains. Intersects maps to Not(Disjoint), Contains(a,b) maps to Within(b,a), and the rest correspond directly to the Clementini relationship.
If the envelope of the query geometry intersects the envelope of the target geometry, esriSpatialRelEnvelopeIntersects equals true.
Specify esriSpatialRelIndexIntersects as the filter spatial relationship if the application is prepared to deal with features that do not intersect the query geometry, as long as all features that do intersect the query geometry are returned. This indicates to the database that only the primary filter based on the spatial index needs to be applied and results in faster query execution. This can be appropriate for drawing applications that rely on clipping to do the secondary filtering.
Specify esriSpatialRelRelate as the filter spatial relationship if the application wants to specify the relationships between the topological interior, boundary, and exterior of the query geometry and the topological interior, boundary, and exterior of the target geometry, using the dimensionally extended nine intersection model. The spatial relationships between the components are specified using a string of nine characters that is set as the value for the esriSpatialRelDescription property of the filter.
The characters are from the alphabet {T, F, *} and indicate the dimension of the point set resulting from the intersection of the two components that map to that character position. No intersection is indicated by F, T indicates intersection, and asterisk (*) indicates don't care. The mapping of components to character position in the string is shown in the illustration to the left. The character string is constructed by reading the entries in the 3 by 3 matrix in the order left to right and top to bottom. The values in the following illustration translate into the nine-character string reading from left to right and top to bottom (TT*TT***):
Some of the spatial relationships exposed to the end user in the TODO ArcMap Select By Location dialog box do not correspond directly to the basic Clementini relationships described previously. These spatial relationships can be implemented using the Clementini spatial filter relationships combined with preprocessing and post processing. Preprocessing is used to assemble the appropriate query geometry (for example, in the case of distance-based relationships, using buffer). Post processing can be used to further restrict retrieved geometries returned by the Clementini operator. The following illustration shows examples of such processing—relationships between the query and target geometries:
The SpatialRelDescription property is only used when SpatialRel is set to esriSpatialRelRelation. You can use it to define various complex spatial relationships. The SearchOrder property determines whether the spatial part of the query is performed before the attribute part of the query. By default, the spatial relationship is tested first, but in the case of queries where the attribute criteria are more specific than the spatial, it is better to change the SearchOrder. An example of this kind of query could be; find all worldwide cities with population greater than a million that are not in Spain.
If you want to query a feature class based on a collection of shapes, for example, select the cities within the selected states, you have several different options. One option is to apply successive spatial filters for each query shape. Another option is to make a single multipart query shape from the collection of original query shapes, then use a single spatial filter.
The following code example shows how to form a single geometry from the selected features in a layer:
[Java]
EnumFeatureGeometry enumGeom = new EnumFeatureGeometry();
enumGeom.bindGeometrySource(null, flayer.getSelectionSet());
GeometryEnvironment geomFactory = new GeometryEnvironment();
IGeometry geom = geomFactory.createGeometryFromEnumerator(enumGeom);

Selections

A SelectionSet object allows an application to reference a selected set of rows belonging to a single table or feature class.
Selection sets are normally used throughout ArcObjects when a temporary subset of rows or features is required for an operation. The selection set only applies to a single table; you cannot sensibly combine two selection sets from different tables.
A selection set can be based on a set of ObjectIDs that correspond to the selected rows or on a set of Row objects, instantiated and referenced by the selection set. In either case, the selection set provides methods to iterate over the set of Row objects in the selection. The SelectionType property of a selection set—specified by an application when it creates the selection set—determines the type of representation (ObjectIDs or Row object references) used by the SelectionSet.
A selection set is typically created from a table or feature class using the Select method on the table. A query filter is used to specify the subset of rows to include in the selection set. See the following code example:
[Java]
SelectionSet selection = new SelectionSet(fclass.select(qfilter,
    esriSelectionType.esriSelectionTypeHybrid,
    esriSelectionOption.esriSelectionOptionNormal, wksp));
An application can create multiple SelectionSets on a Table or FeatureClass coclass. The SelectionSets reference their target table, but the latter have no knowledge of the selection sets that reference them. Applications are responsible for associating the created selection sets with the target table as appropriate. For example, a FeatureLayer in TODO ArcMap holds a reference to a geodatabase FeatureClass and also to a SelectionSet that it creates on the feature class—at draw time the selected features are retrieved and drawn in a distinguished manner.
The ISelectionSet interface is used to manage and query the selection set. The Search method is used to iterate over the rows in the selection set and returns a cursor. The Search method takes a query filter that can be used to further restrict the set of rows in the selection that are returned for ID set selections. Using a query filter with hybrid selections forces the representation of the selection to become an ID set selection.
The Select method is used to create a new selection based on a subset of the current selection using a query filter to specify the restriction. The Add, AddList, and RemoveList methods can be used to alter the selection set by adding and removing rows specified by object IDs. The Combine method can be used to combine two SelectionSets using the standard set operations of union, intersection, difference, and symmetric difference. Only use the Combine method on two selection sets from the same target—it doesn't make sense to mix lists of IDs from different datasets.
The ISelectionSet2 interface provides a method update that creates an Update cursor on the selection set; this can be used to update and delete rows from the table or feature class of the selection set.
The following code example returns the average population of the selected features in a counties feature layer and shows a transition from using TODO ArcMap objects to using the geodatabase data access objects:
[Java]
SelectionSet sset = new SelectionSet(flayer.getSelectionSet());
ICursor[] fcursor = new ICursor[1];
sset.search(null, true, fcursor);
DataStatistics dstats = new DataStatistics();
dstats.setCursorByRef(fcursor[0]);
dstats.setField("POP1990");
System.out.println(dstats.getStatistics().getMean());
As described in this section, the main interface for geodatabase selection sets is ISelectionSet; however, there are other similarly named interfaces in ArcObjects. The following illustration summarizes these interfaces:

QueryDef

A QueryDef object represents a database query on one or more tables or feature classes. A QueryDef can be evaluated, resulting in the execution of the query on the database server. The results of the query are returned to the application as a cursor. The application can iterate over the cursor to fetch the Row objects in the result set of the query. The Row objects returned by a cursor on a QueryDef are always of type esriGeoDatabase.Row and never have custom behavior or support additional interfaces, even if the table names specified in the QueryDef correspond to tables representing ObjectClasses with behavior. The Row objects returned by evaluating a QueryDef are read-only and do not reference a parent table—the Store method may not be called on them. Attempting to store a Row object returned by evaluating a QueryDef results in an error.
The primary use of QueryDefs is to directly evaluate database queries on arbitrary tables. They can be used to join tables with the assurance that the join query executes in the underlying RDBMS. All tables in a QueryDef must belong to the same workspace (RDBMS). A QueryDef can include geometry fields in the specification of the list of fields to be returned but may not include geometry fields in the where clause specification unless the underlying DBMS is a spatially extended DBMS that supports geometric types, and unless the geometry fields for feature classes are using those native DBMS geometry types for storage.
The IQueryDef interface is used to set up and define the query and also provides an Evaluate method that is used to execute the query, returning a cursor.
The following code example shows how to create a QueryDef that defines a join between USA counties and states—a valid pointer to the workspace containing the data is assumed:
[Java]
QueryDef qdef = new QueryDef(fworkspace.createQueryDef()); 
    //QueryDef qdef = (QueryDef) fworkspace.createQueryDef();
qdef.setTables("Counties, States"); 
    // TODO does not seem to be working for shapefiles or .mdb.
qdef.setSubFields("COUNTIES.Shape, COUNTIES.NAME, STATES.STATE_ABBR");
qdef.setWhereClause("COUNTIES.STATE_FIPS = STATES.STATE_FIPS");
QueryDef objects cannot be cocreated—can only be created from the IFeatureWorkspace interface, which guarantees that all tables in the query are in the same workspace.
The SetSubFields property is optional when creating QueryDef objects. The default value is asterisk (*), which means all fields are returned.
The OpenFeatureQuery method on a workspace (available in the IFeatureWorkspace interface) can be used to create a FeatureClass that is based on a QueryDef. This type of feature class can be added to a map—as a FeatureLayer—and can be used to visually represent the results of a database join query (this type of FeatureClass is similar in concept to an ArcSDE view).
The following code example adds a new layer to a map based on the QueryDef created in the preceding code example. The IQueryDef.SetSubFields property must define one and only one spatial field to create the feature class.
[Java]
FeatureDataset fdataset = new FeatureDataset(fworkspace.openFeatureQuery(
    "My counties join", qdef));
FeatureClass fclass = null;
if (fdataset.getClassCount() != 1){
    System.out.println("Failed to create feature class by query");
    System.exit(0);
}

fclass = new FeatureClass(fdataset.esri_getClass(0));
Map map = new Map();
FeatureLayer flayer = new FeatureLayer();
flayer.setFeatureClassByRef(fclass);
map.addLayer(flayer);
The SQL syntax used with QueryDef objects is the same as the underlying database holding the data. An application can use the ISQLSyntax interface on a workspace to determine information about the SQL syntax for the database, such as the delimiter character used in qualifying table and field names and the identifier quote character.
QueryDefs represent a subset of the queries that can be made against an SQL database using the SQL SELECT statement. QueryDefs map onto simple SQL select statements of the form: SELECT <field names> FROM <list of table names> WHERE <where-clause referencing only tables in from list of tables>.
QueryDefs do not guarantee to support SQL statements that do not map onto the previous simple form. In particular, QueryDefs do not guarantee to support ORDER BY and GROUP BY clauses embedded within the WhereClause property, nested SELECT statements, or correlated subqueries in the WhereClause property, AS keywords embedded in the SubFields property, the use of table aliases in the Tables property, the use of Aggregate functions (for example, MIN, MAX, and SUM), or the use of DISTINCT clauses. Support of such capabilities is not guaranteed across all configurations and applications that rely on this risk failure.

Relationships

The following illustration shows Relationship objects:
A RelationshipClass is an association between two object classes (origin and destination class). The relationship class represents a set of relationships between the objects belonging to two classes. See the following illustration showing RelationshipClass:
You can create a relationship class with IRelationshipClassContainer or IFeatureWorkspace. RelationshipClass objects implement IDataset (useful for getting the name or the workspace), but they do not implement IClass (unless they are attributed). This is because a nonattributed relationship class does not have any fields of its own.
The IRelationshipClass interface provides information about a relationship class, functionality to create and delete individual relationships, and methods to find related objects. The members of this interface can be split into the following three logical groups: properties that correspond to how the relationship class was created, object-to-object methods that deal with individual relationships, and the relationship rules methods.
See the following illustration showing IRelationshipClass:
The GetOriginPrimaryKey, GetOriginForeignKey, Get DestinationPrimaryKey, and GetDestinationForeignKey properties can be complicated—usage is different depending on whether the relationship class is attributed. See the following illustration showing nonattributed and attributed relationship classes:
The object-to-object methods, such as GetObjectsRelatedToObjectSet, use the ISet interface, which manipulates a set of generic objects. When adding objects to a set with a cursor, turn off the cursor recycling, as shown in the following code example (deletes all the relationships for features with areas less than a certain value):
[Java]
QueryFilter qfilter = new QueryFilter();
qfilter.setWhereClause("SHAPE.AREA < 25");
FeatureCursor fcursor = new FeatureCursor(fclass.search(qfilter, false));
Set fset = new Set();
Feature feature = (Feature)fcursor.nextFeature();
while (feature != null){
    fset.add(feature);
    feature = (Feature)fcursor.nextFeature();
    if (feature != null)
        System.out.println("State name = " + feature.getValue(feature.getFields()
            .findField("STATE_NAME")));
}

fset.reset();
System.out.println("number of features = " + fset.getCount());
RelationshipClass rclass = new RelationshipClass(fworkspace.openRelationshipClass(
    "GDB.CitiesInStates"));
Set relatedFeatures = (Set)rclass.getObjectsRelatedToObjectSet(fset);
Object rfeat = relatedFeatures.next();
if (rfeat != null){
    int cityIndex = (new Feature(rfeat)).getFields().findField("CITY_NAME");
    int stateIndex = (new Feature(rfeat)).getFields().findField("STATE_NAME");
    while (rfeat != null){
        System.out.println((new Feature(rfeat)).getValue(stateIndex) + " = " + (new
            Feature(rfeat)).getValue(cityIndex));
        rfeat = relatedFeatures.next();
    }
}

rclass.deleteRelationshipsForObjectSet(fset);
The Identify Results dialog box in ArcMap allows you to find objects related to other objects through a relationship class. See the following screen shot:
When using CreateRelationship, remember that this operation writes a value into the foreign key field. It is possible that you could overwrite and delete an existing relationship. Similarly, DeleteRelationship removes the foreign key value; therefore, that field must allow null values unless you want to ensure that all objects in the class belong to relationships.
The ArcMap editor's property inspector allows you to find, add, and remove relationships for an object. See the following screen shot:
The IRelationshipClass2 interface provides a method to get matching objects. See the following illustration:

An AttributedRelationshipClass is a special relationship class and is also a type of table (relationship table). For nonattributed relationship classes, the relationships are stored with the objects in the foreign key values. For attributed relationship classes, the relationships are defined by the objects in conjunction with the rows in the relationship table. See the following illustration:
A reliable way to verify that you have an AttributedRelationshipClass object is shown in the following code example:
[Java]
if {
    pRelClass instanceof ITable
}

System.out.println("Attributed Relationship Class")
    ;
The IRelationshipClass.IsAttributed property only returns true if there are extra relationship attributes beyond those required to relate the objects. The IRelationshipClass.GetRelationship method is useful for accessing the relationship attributes. See the following illustration:
A relationship represents a pair of related objects or features. Relationship is an abstract class that covers SimpleRelationship and AttributedRelationship objects.
The IRelationship interface provides read-only information about a relationship. It is most useful with attributed relationships since it can form a bridge between the attribute information, which is in row form, and the related objects. When dealing with relationships, you will normally use the IRelationshipClass interface rather than IRelationship. See the following illustration:
 
The SimpleRelationship object represents a pair of related geodatabase objects or features. There are no attribute values associated with the relationship. Do not cocreate a simple relationship, use IRelationshipClass.CreateRelationship instead.
The AttributedRelationship object is a type of row that represents a pair of related objects or features with extra information about the pairing. The extra information is stored in the row.
Do not cocreate an attributed relationship, use IRelationshipClass.CreateRelationship instead. The IRelationshipClassEvents interface provides information as to when two objects are related or unrelated and when attributes on an attributed relationship are modified. Use this interface to listen to the events on the relationship class you care about.

Domains and validation rules

The following illustration shows domain and validation rule objects:
Rules are associated with object classes and are used during the process of validating objects in an object class. The following are the four categories of rules that are subclassed from the Rule abstract class:
Associating a rule with a class does not guarantee all objects in the class will be valid; the validation process still needs to run through the Editor toolbar or with IValidation.Validate. Through the IValidation interface (found on the Object class), the set of currently defined rules can be accessed, new rules can be added, and objects can be validated.
The following code example extracts the rules defined for a layer and prints the rule type and helpstring associated with the rule:
[Java]
FeatureClass fclass = new FeatureClass(fworkspace.openFeatureClass("GDB.States"));
IEnumRule rules = fclass.getRules();
IRule rule = rules.next();
while (rule != null){
    if (rule instanceof IAttributeRule){
        System.out.println("Attribute rule - " + rule.getType() + "-" +
            rule.getHelpstring());
    }
    else if (rule instanceof IRelationshipRule){
        System.out.println("Relationship rule - " + rule.getType() + "-" +
            rule.getHelpstring());
    }
    else if (rule instanceof IJunctionConnectivityRule){
        System.out.println("AttJunctionConnectivity rule - " + rule.getType() + "-" 
            + rule.getHelpstring());
    }
    else if (rule instanceof IEdgeConnectivityRule){
        System.out.println("EdgeConnectivity rule - " + rule.getType() + "-" +
            rule.getHelpstring());
    }
    rule = rules.next();
}
Creating a class extension can extend the types of rules that can be defined for an object class. By implementing IObjectClassValidation (along with IClassExtension), any type of custom validation rule can be coded.

Attribute rules and domains

An attribute rule applies an attribute domain to a field of an object class. The AttributeRule class is used to define attribute specific rules on an object class. This type of rule applies a specified domain to a field name with a specific subtype. See the following illustration:
Domains can be used to limit the attribute values to a set of valid values or to a range of values. Domains can also define how values in the field are distributed during a split. The process of associating a domain with a field in an object class creates an AttributeRule as a side effect—thus, it is generally not the case that users must explicitly create AttributeRules.
A domain is used to specify the permissible values that a field in an object class may take. A Domain is an abstract class that defines an interface used by RangeDomain and CodedValueDomain coclasses to constrain the permissible values that may be associated with a particular field on an object or feature class. Domains are assigned on a subtype basis. See the following illustration:
The IDomain interface provides access to the common properties shared across both types of domains. Each of the properties are read-write except for the Type property. When creating and assigning a domain to a particular field, the client is required to set the Name and FieldType properties.
A range domain is used to specify the legal minimum and maximum values that a field can have.
A coded value domain is used to specify a set of permissible values that a field can take. Domains are used by the ArcMap property inspector to constrain the values that the user can enter for a field, as well as during the validation process within the geodatabase. A domain can be shared by any number of fields. Domains are associated with a Field object. Domains are added to a dataset at the workspace level through IWorkspaceDomains.addDomain.
RangeDomains can be associated with fields that are numeric fields (such as esriFieldTypeSmallInteger or esriFieldTypeDouble) or date fields. RangeDomains cannot be associated with string or character fields (esriFieldTypeString).
CodedValueDomains store a set of (value, name) pairs that represent the discrete values that a field can take. The value is what is persisted inside a field and the name is what is displayed by the ArcMap property inspector. The name can be considered to be a human-readable string that describes what the value represents. In contrast to RangeDomains, CodedValueDomains can also be associated with string fields (esriFieldTypeString)—the value can be a string.
The ArcMap Identify dialog box and editor's property inspector make use of coded value domains to display the human-readable description of values for an attribute. The object inspector also provides a list of valid values for users to select when editing an attribute with a coded value domain. See the following screen shot:
The following code example shows how a user can use these properties to display all the (value, name) pairs associated with a CodedValueDomain:
[Java]
CodedValueDomain domain = (CodedValueDomain)fld.getDomain();
Object value = null;
String name = null;
for (int i = 0; i < domain.getCodeCount(); i++){
    value = domain.getValue(i);
    name = domain.getName(i);
    System.out.println("value: " + value + " name: " + name);
}
Domains are managed at the workspace level. The following screen shot shows the ArcCatalog user interface for creating, deleting, and modifying domains:

Relationship rules

A RelationshipRule constrains the cardinality between two subtypes that participate in a RelationshipClass. Thus, if the RelationshipClass is a one-to-many relationship, a RelationshipRule may, for example, constrain the cardinality between two subtypes to be one–three. The RelationshipRule may not conflict with the RelationshipClass. For example, a one-to-many RelationshipClass may not have any associated relationship rules that constrain the cardinality to be two-to-two. One RelationshipRule is necessary for each subtype pair that participates in the RelationshipClass. See the following illustration:
The IRelationshipRule interface inherits from IRule. This interface provides access to the various parameters of a relationship rule that are used to refine the cordialities between subtypes participating in the RelationshipClass. Use this interface when you want to set or retrieve these parameters.

Connectivity rules

A connectivity rule constrains the type of network connectivity that may be established between edges and junctions in the geometric network. See the following illustration:
In a geometric network, any edge can connect to any junction. ConnectivityRules are used to constrain the permissible connectivity between edges and junctions. Connectivity rules can only be established between network feature classes.
The following are the two types of connectivity rules that can be applied:
The JunctionConnectivityRule class is a type of ConnectivityRule that constrains the possible valid network connections that may exist between a pair of edge and junction subtypes. It may also constrain the cardinality of the connectivity relationships.
The IJunctionConnectivityRule interface inherits from IConnectivityRule. This interface defines the junction connectivity properties and the valid types of edges that can connect to them. Use this interface when you want to define or manipulate rules between an edge and a junction. See the following illustration:
The EdgeConnectivityRule class is a type of ConnectivityRule that defines the permissible relationship between two edge features. In addition, it specifies all the valid junctions that may exist at the connection point between the two edges. It is also possible to specify the default junction that will be placed at the point of connectivity between the two edges. The IEdgeConnectivityRule interface inherits from IConnectivityRule. This interface defines the two types of edges (they can be of the same type) and the valid junctions that can exist between them. See the following illustration:
DefaultJunctionClassID and DefaultJunctionSubtypeCode define the default junction that will be added at the location where connectivity is established between two edges of the specified type.
The number of junctions associated with the EdgeConnectivityRule is unlimited. Junctions are managed through this interface and are accessed on an index basis (the JunctionCount property, JunctionClassID, and JunctionSubtypeCode index-based properties). It is not possible to remove a junction from the rule—if this is required, the rule must be deleted and re-created, less the junction to be deleted.
The following screen shot shows the ArcCatalog user interface for configuring connectivity rules for a geometric network:
 

Geometric network

A geometric network is a type of graph that is uniquely associated with a logical network, which represents network topology. See the following illustration of a geometric network:
GeometricNetworks are responsible for detecting and maintaining network connectivity among a set of feature classes that participate in the network. When new network features are created, the GeometricNetwork is responsible for detecting endpoint coincidence (in the case of edge features) with other network features, then communicating with the logical network to establish network connectivity. See the following illustration:
The GeometricNetwork is also responsible for managing and validating all connectivity rules.
The most common type of third-party client applications that consume the IGeometricNetwork interface are custom network solvers. The associated logical network can be accessed through the Network property.
The direct accessibility of the logical network obviates the need to expose the functionality of the logical network through redundant convenience methods at the geometric network level. Functionality that is related to the mapping between geometry (found at the feature level) and network elements (found at the logical network level) is necessarily supported outside of the logical network. This is because the logical network does not have any understanding of feature geometry, only logical connectivity.
You can determine the network elements associated with a network feature at a given location through the EdgeElement and JunctionElement properties. If there is more than one network feature of the appropriate type at the location, the edge or junction element that corresponds to the first one encountered is returned.
Complementary functionality is also provided where, for a given edge or junction element, the associated feature geometry is returned via the GeometryForEdgeEID and GeometryForJunctionEID properties, respectively.
In contrast to the results returned by the EdgeElement and JunctionElement methods, the GeometryForEdgeEID and GeometryForJunctionEID properties return an unambiguous result, as only one piece of geometry corresponds to a given element ID (EID) for an element in a logical network.
A final method found on IGeometricNetwork that may commonly be called by third-party client applications is SearchForNetworkFeature. This method, given a point location and a feature type, returns all the network features found in the machine precision of this point. If more than one network feature is coincident with the point, all are returned. The returned network features can span different feature classes—the only restriction is that all features must be of the same feature type.
The IGeometricNetworkErrorDetection interface identifies errors between a geometric network and its logical network.
To maintain correct network connectivity in large production environments, it is necessary to have a collection of tools that will enable the user to detect a variety of connectivity problems in a geometric network. In production environments, it is often impractical to drop the network and rebuild when connectivity problems are encountered during general editing of the network. For this reason, it is necessary to provide a set of tools that enables the end user to detect and repair such problems.
Philosophically, there should not be any need for such tools—the network should always be correct. From this standpoint, the geodatabase will not waver. However, the following are the circumstances where this may be violated:
The CreateErrorTable method is used to create a table that can be used to persist information related to corrupt network features (using a fixed table schema) with the specified name. Such network error information can only be persisted by the geometric network in a table with this schema. This table is user managed and should remain unversioned.
The DeleteNetworkElements method takes an ISet of ISelectionSets. All of the network features contained in the various selection sets will have their network elements deleted from the logical network. The primary reason why one would want to do this is to correct the geometry of an edge feature that was loaded (prior to ArcGIS 8.1) with corrupt polyline geometry.
If network connectivity errors are found in the geometric network, they can generally be corrected through the use of the RebuildConnectivity method on the IGeometricNetworkConnectivity interface. This method takes an envelope that should contain all the network features for which connectivity should be rebuilt.
A graph is a set of topologically related feature classes. The Graph class is an abstract class that factors behavior and attribution common to the different types of topological collections within the geodatabase.
The IGraph interface specifies the attributes and properties expected on all the different types of topological collections within the geodatabase. These attributes and methods are not unique to a particular type of topology. It is not expected that third-party client applications call many of these methods. The primary clients of these methods on this interface are ArcMap, ArcCatalog, and the polymorphic implementations of the features managed by the Graph class.

Network features

NetworkFeature is an abstract component that supports network connectivity and participates in a geometric network. See the following illustration:
 
The INetworkFeature interface is supported at the NetworkFeature level in the geodatabase—all features participating in a GeometricNetwork support this interface. Because each NetworkFeature may be enabled (can trace through) or disabled (cannot trace through) in the logical network, the Enabled property is read–write. Although a complex edge can correspond to one or more network elements, setting the Enabled property enables or disables all associated network elements. It is not possible to individually set the enabled or disabled status of an individual network element associated with a complex network feature through this interface.
When a NetworkFeature is created and added to a GeometricNetwork coclass, the GeometricNetwork calls the CreateNetworkElements method on the NetworkFeature. It is not necessary for a custom feature developer to override this method in their implementation.
If network features are programmatically created—for example, using a sequence similar to IFeatureClass.CreateFeature, setting the feature's shape, and calling the Store method on the feature—the network feature's spatial reference must match that of the containing FeatureClass.
More specifically, if you call IGeometry.Project on the geometry prior to it being set as the feature's shape, ensure that the SpatialReference passed as an argument to the Project method match the FeatureClass. It is not always the case that the map's SpatialReference is the correct one to use—for example, the map may contain two FeatureDatasets with differing SpatialReferences.
Junction features are used to maintain network integrity in a geometric network and are found at the locations that correspond to the endpoints of edge features. They can also be freestanding (unconnected to any edge feature) or connected to complex edges at midspan.
The SimpleJunctionFeature class represents simple junctions on a network that may be added to GeometricNetworks.
The SimpleJunctionFeature class can be aggregated, and possibly overridden, by custom feature developers.
Simple junction features have point geometry and may be connected to any number of other edge features.
A simple junction feature may not be directly connected to another junction feature without an intervening edge feature.
See the following illustration:
The ISimpleJunctionFeature interface contains three properties that are unique to simple junctions.
The EdgeFeatureCount property and EdgeFeature property array are used to specify the connected edge features to the client. The index for EdgeFeature is zero-based.
See the following illustration:
 
The following code example shows how to use this information to display the object IDs of the connected edge features:
[Java]
SimpleJunctionFeature simpleJunction = new SimpleJunctionFeature(feat);
SimpleEdgeFeature edgeFeature = null;
for (int i = 0; i < simpleJunction.getEdgeFeatureCount(); i++){
    edgeFeature = (SimpleEdgeFeature)simpleJunction.getEdgeFeature(i);
    System.out.println("EdgeFeature " + edgeFeature.getOID());
}
Edge features correspond to features with polyline geometry that are part of the network topology in a geometric network. See the following illustration:
Edge features have two or more connected junction features—one at each location corresponding to the endpoints of their polyline geometries. Complex edges can also have any number of connected mid-span junction features. An EdgeFeature is an abstract class. See the following illustration:

The IEdgeFeature interface must be supported by both simple and complex edges. This interface is found on the EdgeFeature abstract class. The properties found on this interface are intended to facilitate network feature navigation for client applications.
The FromToJunctionEIDs property hands back the FROM and TO junction EIDs; it is more efficient to access this property than to call FromJunctionEID and ToJunctionEID. These properties are generally computationally expensive. For certain clients (that is, those that do not require access to the geometry, attributes, or feature class associated with the network feature), it may prove more advantageous to directly utilize the logical network when performing navigation between large numbers of network features—for example, this is the case with network solvers.
The Update method is reserved for internal consumption (during the process of updating the shape and storing the result)—there is no need for clients to call this method directly.
Simple edge features correspond to features with polyline geometry that are part of the network topology in a geometric network. Simple edge features have two connected junction features—one at each location corresponding to the endpoints of their polyline geometries.
Junction features connected at mid-span are not allowed. If you attempt to connect a junction at mid-span on a SimpleEdgeFeature, a split operation occurs (the original SimpleEdgeFeature is deleted and replaced by two new SimpleEdgeFeatures that are commonly connected at the junction feature that caused the subdivision). See the following illustration:
Complex edge features correspond to features with polyline geometry that are part of the network topology in a geometric network. Complex edge features have two or more connected junction features—one at each location corresponding to the endpoints of their polyline geometries. They can also have any number of connected mid-span junction features. See the following illustration:
Connecting a junction feature to a ComplexEdgeFeature does not result in a physical subdivision of the edge; instead, it results in a logical subdivision (that is, new edge elements in the logical network that are associated with the complex edge).
The geometry of ComplexEdgeFeatures may not be self-intersecting; there can be discontinuities with the geometry (they can be multipart), and the geometry may not have the same start and stop vertex (that is, a closed loop).
The IComplexEdgeFeature interface is supported on a ComplexEdgeFeature. The GeometryForEID property allows clients to obtain the portion of the complex edge's geometry that corresponds to a specified EID. This is useful for network solvers in particular. The JunctionFeature property array is a mechanism for clients to obtain all the junction features associated with the complex edge.

Topology

A topology is a collection of simple feature classes in the same feature dataset that participate in topological relationships with a set of rules that govern those relationships. See the following illustration:
Topologies can have multiple feature classes in the same topological role. A feature dataset may have multiple topologies, but a feature class can only belong to one topology. Each topology has one associated topology graph. The topology graph is a planar representation of the geometries in the feature classes participating in a geodatabase topology. See the following illustration:
 
When new features are created, edited, or deleted, the topology is responsible for creating or modifying a dirty area that encompasses the envelope of the feature. A dirty area is a special type of feature under which, the state of the topology is unknown. See the following illustration:
 
Features that are covered by dirty areas can still be edited and queried, but their topological relationships cannot be guaranteed to be correct. A dirty area must be validated to discover the topology of its underlying features.
The Topology object is not cocreateable—topologies must be created through ITopologyContainer.CreateTopology.
The ITopology interface provides properties of a topology and methods for adding feature classes and validating dirty areas.
The following code example shows how to obtain a reference to a topology in your feature workspace:
[Java]
FeatureDataset fdataset = new FeatureDataset(fworkspace.openFeatureDataset("GDB.USA")
    );
Topology topology = (Topology)fdataset.getTopologyByName("GDB.USA_Topology");
The AddClass method is used to add a feature class to the topology, with the specified weight and ranks.
Nonsimple feature classes, such as annotation, and dimension and geometric network feature classes cannot be added to a topology. Object classes or tables and versioned simple feature classes, cannot be added to a topology. After a populated feature class is added to a topology that has been validated, in whole or in part, the state of the topology will be changed and a dirty area corresponding to the extent of the feature class will be created. If an unpopulated feature class is added to a topology, the topology's state will not change and no dirty area will be created. The AddClass method cannot be called on versioned topologies in ArcSDE, but can be called on nonversioned topologies in ArcSDE and topologies in a personal geodatabase.
Topologies support the IFeatureClassContainer interface that can be used to return the feature classes participating in the topology.
The Cache property returns a reference to the topology graph of the topology. The topology graph can be used for working with topological primitives, such as edges and nodes.
The ClusterTolerance property returns the tolerance that was specified when the topology was built. The ClusterTolerance of the topology cannot be changed. To modify the tolerance, the topology must be deleted and rebuilt with the new ClusterTolerance.
The DirtyArea method returns the dirty area polygon of the topology. The DirtyArea property requires an IPolygon object as input. The IPolygon can correspond to the extent of the topology or a subset of the extent. If there is no dirty area intersecting the specified area, an empty polygon is returned. The dirty area polygon that is returned can be a multipart polygon.
The following code example demonstrates how to obtain the DirtyArea for the entire topology:
[Java]
Polygon polygon = new Polygon();
polygon.setRectangle(topology.getExtent());
Polygon dirtyPoly = (Polygon)topology.getDirtyArea(polygon);
Each topology has a maximum number of errors that can be generated on Validate, which can be determined through the MaximumGeneratedErrorCount property.
MaximumGeneratedErrorCount can only be specified when a topology is created programmatically. All topologies created with the New Topology wizard in ArcCatalog have a MaximumGeneratedErrorCount of –1, indicating no limit to the number of errors that can be generated. As with the ClusterTolerance, the MaximumGeneratedErrorCount property cannot be changed, a topology must be deleted and rebuilt to specify a new value.
The RemoveClass method removes the specified class from the topology. While RemoveClass removes any topology rules and errors associated with the class, it will not result in the creation of a dirty area, nor will the state of the topology change.
The State property indicates the current status of the topology—whether the topology has been validated and if so, whether any topology errors have been discovered.
ValidateTopology validates the dirty area of the topology in the area specified by the AreaToValidate envelope. ValidateTopology evaluates all the rules and produces any topology errors corresponding to areas in which a rule has been violated. The ValidateTopology function returns the envelope of the validated area. If an empty envelope is supplied, ValidateTopology returns an empty validated area.
ValidateTopology can be performed outside of an edit session on topologies in personal geodatabases or on topologies in ArcSDE geodatabases that have not been registered as versioned. Once a topology is registered as versioned, ValidateTopology must be performed in an edit session and bracketed in an edit operation. The IWorkspaceEdit or IEditor interfaces can be used to manage edit sessions and edit operations.
An entire topology can be validated by supplying the envelope of the extent of the topology. See the following code example:
[Java]
topology.validateTopology(topology.getExtent());
By supplying a polygon object to the ITopology.GetDirtyArea property, the dirty area at a particular location can be returned. The envelope of the returned dirty area polygon can then be passed into ValidateTopology. See the following code example:
[Java]
Polygon polygon1 = new Polygon();
polygon.setRectangle(topology.getExtent());
Polygon dirtyPoly1 = (Polygon)topology.getDirtyArea(polygon1);
topology.validateTopology(dirtyPoly1.getEnvelope());
The ITopologyRuleContainer interface provides access to members for adding, removing, and returning topology rules from a topology. This interface also provides access to members that control the promotion and demotion of topology errors and exceptions.
The IsCanAddRule method returns a Boolean value indicating if the topology rule is valid with respect to the existing rules. This method returns false if the following occurs:
The AddRule method is used for adding a new rule to a topology. The addition of the new rule results in a dirty area created for the extent of the entire topology and a change to the state of the topology to esriTSUnanalyzed.
The DeleteRule method removes the specified rule from the topology, resulting in a dirty area created for the extent of the entire topology and a change to the state of the topology to esriTSUnanalyzed.
The DemoteFromRuleException method demotes the specified exception from being an exception to an error feature. On a topology in an ArcSDE geodatabase, call DemoteFromRuleException in an edit session and edit operation.
The PromoteToRuleException method promotes an error feature from an error to an exception. On a topology in an ArcSDE geodatabase, call PromoteToRuleException in an edit session and edit operation.
See the following illustration showing error features and exceptions for must not have dangles rule:

The ITopologyClass interface provides read-only access to the properties of feature classes in a topology. Most of these properties are specified when the feature class is added to the topology.
The ITopologyContainer interface can be used to manage and create topologies in a feature dataset. If you want to browse for the set of topologies in a feature dataset, it is not necessary to open the feature dataset and call the methods on ITopologyContainer. The IFeatureDatasetNames2.GetTopologyNames method can be used to obtain this information. Give careful consideration when specifying the parameters to create a topology. Once the topology is built, none of the parameters can be modified. To change properties, such as cluster tolerance, delete the topology and rebuild with the new parameters.
The ITopologyProperties interface provides access to additional properties of a topology not supplied through the ITopology interface, such the enumeration of feature classes and spatial reference of the topology.
The ITopologyWorkspace interface provides access to the OpenTopology method that allows you to open a topology in a workspace given the topology's name. Use this interface to open a topology when you only have a reference to a workspace object. For ArcSDE geodatabases, the fully qualified name can be used to return topologies owned by specific users. If multiple topologies with the same name and owned by different users exist in the geodatabase, OpenTopology returns the topology owned by the connected user if an unqualified name is supplied.
The ITopologyErrorFeature interface provides access to the read-only properties of topology error features. Topology error features represent violations of topology rules and are discovered during the validation process. Error features cannot be edited directly; therefore, while you can QueryInterface for interfaces, such as IFeature on a TopoloyErrorFeature, calling methods, such as IFeature.GetValue or IFeature.Store will fail.
The only modification that can be made to a topology error feature is to mark it as an exception using the ITopologyRuleContainer.PromoteToRuleException. Conversely, exceptions can be marked as an error by passing it as an argument to ITopologyRuleContainer.DemoteFromRuleException.
The OriginID and DestinationID properties represent the object class IDs of the origin and destination feature classes of the topology rule of which the error feature is in violation. The OriginOID and DestinationOID properties represent the object IDs of the origin and destination features that created the topology error.
In general, all topology errors for which only the origin class has been specified returns values for the OriginID and OriginOID properties and a value of zero for the DestinationID and DestinationOID properties. The exception is for topology errors generated from the esriTRTNoGaps rule, which returns a value of zero for the OriginID, DestinationID, and object ID (OID) properties. In addition, topology rules whose origin and destination feature class have been specified generally returns zero for the destination feature class properties. The following are the exceptions to this rule:
The exception to both of these statements is the esriTRTAreaAreaCoverEachOther rule, which may generate topology errors referencing the origin or destination feature class.
The ErrorID of a topology error feature is not unique across all topology error features in the topology, but is unique for each topology error feature geometry type. While a topology error feature with polygon geometry can have the same ErrorID as a topology error feature with point geometry, the ErrorID will be unique for all topology error features with polygon geometry. Combining the ErrorID and ShapeType of a topology error feature results in a unique value in the topology.
The TopologyRule class is used to define the permissible spatial relationships between features in a topology. Topology rules can be defined with a single feature class or between two feature classes. Topology rules can also be defined to the subtype level of a feature class. Topology rules have an origin and a destination feature class, either of which can be set to the subtype level. Depending on the type of topology rule that is implemented, the destination feature class properties may be irrelevant. See the following illustration:
The ITopologyRule is the main interface for creating and returning information about a topology rule. Use this interface to create a new topology rule or return the properties of existing rules.
The IsAllDestinationSubtypes property specifies if the rule applies to all subtypes in the destination feature class. By default, IsAllDestinationSubtypes is false and the DestinationSubtype property (get/set) points to the default subtype. If IsAllDestinationSubtypes is explicitly set to False, the DestinationSubtype property (get/set) must be set or the rule will be invalid. IsAllDestinationSubtypes returns the opposite value of the IsDestinationSubtypeSpecified property. If the topology rule is a single feature class rule, IsAllDestinationSubtypes is set to true once the rule is added to the topology.
IsAllOriginSubtypes specifies if the rule applies to all subtypes in the origin feature class. By default, IsAllOriginSubtypes is false and the OriginSubtype property (get/set) points to the default subtype. If IsAllOriginSubtypes is explicitly set to false, the OriginSubtype property must be set or the rule will be invalid. IsAllOriginSubtypes returns the opposite value of the IsOriginSubtypeSpecified property.
The DestinationClassID property (get/set) corresponds to the ObjectClassID of the destination feature class of the topology rule. If the topology rule is a single feature class rule, the DestinationClassID does not need to be set, it will be equal to the OriginClassID by default and if set, will be ignored when the rule is added to the topology. The OriginClassID property corresponds to the ObjectClassID of the origin feature class of the topology rule. Every topology rule will have an OriginClassID.
OriginSubtype and DestinationSubtype correspond to the origin and destination subtypes of the topology rule. Setting the OriginSubtype or DestinationSubtype results in the corresponding SubtypeSpecified property returning true. If AllOriginSubtypes or AllDestinationSubtypes is set to true, the value specified for OriginSubtype or DestinationSubtype will be ignored. The ErrorShapeTypes method indicates the error shape types that can be produced by the topology rule. If the rule supports a particular shape type, it returns a value of true.
The GUID property is read-only and returns the unique, geodatabase controlled value that is set when the rule is added to the topology using ITopologyRuleContainer.AddRule. The GUID value can be used to return its associated topology rule using ITopologyRuleContainer.GetRuleByGUID. The Name property can be used to assign a user specified string to each rule. By default, the Name property is empty.
The TopologyRuleType property is used to return or set the type of topology rule from the esriTopologyRuleType constants. Every topology has one inherent rule, the esriTRTFeatureLargerThanClusterTolerance rule, which is added implicitly when the topology is created. See the following illustration showing must not overlap rules:

Topology graph

As mentioned previously, the Cache property on ITopology returns a reference to the topology graph of the topology. The topology graph can be used for working with topological primitives such as edges and nodes.
A topology graph is a cached planar representation of the feature geometries participating in a topology, where the topological relationships are known. There is only one graph per topology. It is derived from the Topology object and cannot be cocreated. The TopologyGraph object allows editing of a topology without breaking adjacency or connectivity of the participating features (also known as shared editing). For example, TopologyGraph can be used to edit the shared boundaries of two polygons without breaking the adjacency of their geometries. Additionally, use it to move a set of overlapping routes while keeping all features coincident. There are a number of properties and methods that can be used on the TopologyGraph object and its components to accomplish the following:
A TopologyGraph object is accessed from a Topology object and is constructed for a given extent. It references the topology primitives that are cached. The topology primitive geometries present in memory have been modified, via cracking and clustering, during a round trip to the topology engine. However, it is important to understand that these geometries are not updated on disk. They are updated only if the topology elements are modified and those edits are posted back to disk. For example, you can programmatically move a topology node, which is shared by several features. This edit is cached in memory until the ITopologyGraph.Post method is called. ITopologyGraph.Post propagates the edit to all the features sharing that topology node and the geometries of those features will be updated. See the following illustration:
The TopologyGraph object is derived from a Topology object and is a singleton. As previously described, you can access a topology's topology graph using the ITopology.GetCache method. The topology graph is empty initially and must be built to contain the topology primitives.
For a topology, the topology graph is built on demand with a user-defined envelope bounding its included features. At construction time, the feature geometries are sent to the topology engine, where they are cracked and clustered using the cluster tolerance for the topology. Cracking and clustering is a process where vertices are introduced at each feature intersection and the new and existing vertices are grouped into clusters. This process is necessary to remove ambiguities between features and discover their topological relationships. After cracking and clustering, the features are, at minimum, separated by the cluster tolerance of the given topology. For a second time, the topological relationships between features are discovered and sent back to the client code. The topology primitives (geometry and topological relationships) are persisted in memory for further uses.
Node and edges are the two types of topology primitives or elements that are cached. A TopologyNode is an object holding a reference to an IPoint geometry. It is created at each feature's endpoints as well as at the intersections of feature geometries participating in the topology. The node also contains topological relationships information, such as incident TopologyEdges and corresponding TopologyParents. A TopologyParent is a pointer to a feature class coupled with a feature OID. This couple uniquely identifies a feature part of the topology.
A TopologyEdge is defined as an object holding a reference to an IPolyline geometry (always single part) formed between two TopologyNodes. The edge also references the topological relationships information, such as FromTopologyNode, ToTopologyNode, and TopologyParents. The TopologyEdge also allows its left and right polygons to be identified when appropriate. At any time, the relationship between nodes, edges, and features can be accessed using the TopologyGraph API.
The following illustration shows representations of the TopologyGraph object. Two polyline features are used to construct the topology graph. The TopologyGraph is persisted in memory and contains nine topology primitives: five nodes and four edges. Each TopologyNode knows which features (TopologyParents) were used to construct it. For example, the parents of the center TopologyNode are the two polyline features. The TopologyNode also knows which TopologyEdges are connected to it. The edges, in turn, are aware of their TopologyParents, FromTopologyNode, and ToTopologyNode.
In the following illustration, a polyline feature overlaps the boundaries of two adjacent polygon features, in which the TopologyGraph contains five topology primitives—two nodes and three edges. Each TopologyNode has three TopologyParents—the polyline and both polygons. The black arrow shows the orientation of the polyline feature. The red arrows show the orientation of the TopologyEdges. For example, the central TopologyEdge has three parents (polyline and both polygons). Using this TopologyEdge and the ITopologyEdge.GetLeftParents or ITopologyEdge.GetRightParents method, you can access the blue and green polygons. The orientation of the edge determines which polygon is the left or right parent. A TopologyEdge also knows which TopologyNodes are associated with it. You can use this information to navigate in the TopologyGraph. A topology element can have 1-N TopologyParents. The parents are the features that share geometries at a given location.
The ITopologyGraph interface exposes several methods for interacting with the elements of a topology; therefore, the underlying features participating in the topology. You can access all or selected elements of a TopologyGraph. See the following:
Once you've accessed the topology elements, you can work with their associated topological relationships. Three methods are available. See the following:
As previously discussed, the features associated with a topology element are known as its TopologyParents. Three methods are available providing access to the following:
Topology elements can be moved or transformed in a variety of ways. The methods used vary according to the type of transformation. See the following:
By default, operations done on the TopologyGraph affect all TopologyParents (features) associated with its edited elements; however, there is a way to control which features are affected by a given operation. The TopologyParent selection (used by the Show Shared Features dialog box on the Topology toolbar in ArcMap) can help modify this behavior. The parent selection is defined as the state of the TopologyParents for a given operation. By default, this state is set to true for all TopologyParents. By changing this state to false, some features can be subtracted from the subsequent TopologyGraph operation. This can be done using the ITopologyGraph.SetParentSelected method. The state is reset to its default after any TopologyGraph operation.
Modifying a TopologyGraph element doesn't immediately modify the features on disk. A topology edit exists in memory but the features are not modified until the ITopologyGraph.Post method is called. This method propagates the edits made on the topology element's geometry into the features associated with it (TopologyParents). In basic terms, it replaces the edited feature's geometry with the geometries that went to the topology engine and have the modified shape.
Since all topology primitives are stored in memory, building the TopologyGraph for a large extent is not recommended. For efficiency reasons, the smaller the extent of the TopologyGraph the better; however, some applications can require larger extents. As an alternative, it is possible to build several smaller TopologyGraphs in some cases. The amount of random access memory (RAM) available on your machine is directly correlated to the performance of the TopologyGraph (the more RAM the better).

Data elements

Data elements describe entities that can be used in geoprocessing functions—for example, DEFolder, DETable, and DEShapeFile. These objects are simple structures whose properties describe the actual entity. For instance, DEShapeFile has properties, such as GetExtent and GetSpatialReference. A subset of the data elements describes geodatabase datasets. The classes, DEFeatureClass, DEFeatureDataset, and so on can be used to describe geodatabase datasets. See the following illustration showing DataElement objects:
The workspace and feature dataset are containers of other datasets. Likewise, the DEWorkspace and DEFeatureDataset contains other data elements in their children array (accessible through the IDataElement interface).
Data elements support IXMLSerialize and IPersistStream; therefore, a set of data elements can be serialized in Extensible Markup Language (XML) or binary form.
Data elements can be created in several ways. Data elements are cocreatable and application developers can create new instances of a data element, then fill its properties with appropriate values. In ArcCatalog, the data element associated to a GxObject can be obtained by using the GetDataElement method in the IGxDataElement interface. Lastly, a workspace may implement the IWorkspaceDataElements interface, which can be used to request a data element for the whole workspace or a data element for a particular dataset.
The CatalogPath of a data element contains the path to the dataset. If retrieved from a GxObject, the data element's catalog path corresponds to the path displayed by ArcCatalog when the dataset is selected in the view pane. If retrieved from the workspace, the catalog path will be built. See the following code example: 
[Java]
 / V = [version] / DatasetKeyword = datasetName / ChildDatasetKeyword = datasetName
In the preceding code example, the path elements are separated using a slash mark (/) and the dataset keywords are taken from the list in the following table. The version can be empty if the source is a personal geodatabase.
Dataset types
Keywords
Feature dataset FD
Feature class FC
ObjectClass OC
Relationship class RC
Geometric network GN
Topology TOPO
Raster band RB
Raster dataset RD
Raster catalog RCAT
Toolbox TB
The following code example shows sample catalog paths:
[Java]
 / V =  / FD = USA / FC = Capitals 

 / V = SDE.DEFAULT / FD = Landbase / FC = Parcels
The GetDatasetDataElement method in IWorkspaceDataElements allows client code to create a data element from a name object or from a dataset object. In the first case, only the properties available in the name object will be populated in the resulting data element. See the following illustration:
Set the IsRetrieveFullProperties Boolean property in DEBrowseOptions to false when using a name object as input. See the following code example:
[Java]
IWorkspaceDataElements wdelems = new IWorkspaceDataElementsProxy(workspace);
IEnumDatasetName datasetNames = workspace.getDatasetNames
    (esriDatasetType.esriDTFeatureClass);
datasetNames.reset();

FeatureClassName dname = (FeatureClassName)datasetNames.next();
DEBrowseOptions options = new DEBrowseOptions();
options.setRetrieveFullProperties(false);
options.setExpandType(esriDEExpandType.esriDEExpandNone);
DEFeatureClass defclass = (DEFeatureClass)wdelems.getDatasetDataElement(dname,
    options);
When using a dataset as input, the GetDatasetDataElement method returns a fully populated data element. See the following code example:
[Java]
//FeatureClass fclass = (FeatureClass) dname.open(); // TODO ClassCastException.
FeatureClass fclass = new FeatureClass(dname.open());
options.setRetrieveFullProperties(true);
IDataElement elem = wdelems.getDatasetDataElement(fclass, options);
The GetExpandType property of DEBrowseOptions controls whether data elements should be created for children of the requested data element. Client code can only request immediate children or all descendants. For example, when using the GetWorkspaceDataElement method with immediate children, data elements for tables, feature datasets, and other datasets at the workspace level will be created, but no data element will be created for datasets under the feature datasets. Lastly, the dataset's metadata will be retrieved only if IsRetrieveMetadata is set to true.
The GdbSchemaCreator class can be used to create the schema given an array of data elements.
In the following code example, the array has one DEFeatureClass instance. The schema creator requires full properties to be retrieved to create the datasets. The catalog path should be a geodatabase complaint catalog path.
[Java]
GdbSchemaCreator creator = new GdbSchemaCreator();
Array deArray = new Array();
deArray.insert(0, defclass);

IEnumNameMapping[] nameMappings = new IEnumNameMapping[1];
boolean[] hasConflict = new boolean[1];
creator.generateNameMapping(workspace, deArray, null, nameMappings, hasConflict);
creator.createSchema(workspace, nameMappings[0]);
The association between a feature class and a topology has extra attributes—for example, the rank of the feature class. The association of a feature class and a geometric network also has extra attributes—for example, the enabled field. These are attributes of the feature class membership in a controlling entity, be it the topology or the geometric network. They are attributes of the membership because they wouldn't exist if the feature class were not a member of the controller. The table data element has an array of controller memberships.
Each membership contains the data about the relationship between the feature class and the controlling entity—for example, rank or enabled field.
Some properties of data elements are instances of other classes in the geodatabase library. For example, the fields of a DETable are instances of the Fields and Field classes. This is done whenever the existing ArcObject class is a simple cocreatable structure that can be used detached from any dataset. Other examples are the rules (connectivity, topology), weights and weight associations, domains, and indexes.
Simple classes were created for other geodatabase constructs that are not datasets, but required to be described as properties of data elements. Such classes have the GP prefix. For example, the GPSubtype class represents a geodatabase subtype and the table data element has an array of GPSubtypes. Other examples of these classes are GPTopologyMembership, GPGeometricNetworkMembership, and GPRelationshipClassKey.
Data elements are simple structures with very little behavior. Caution must be exercised when setting their properties because there is little validation code. For example, a DEGdbTable could be defined to have a SubtypeFieldName, but no actual subtypes be placed in its Subtype array. Such instance would be invalid for most purposes. The following are the data element objects in the geodatabase:

TIN

The following illustration shows TIN objects, which contains objects for accessing and working with TINs:
The TIN coclass is used for surface modeling and other forms of spatial analysis. A TIN is comprised of adjacent, nonoverlapping, triangles. It is a complete planar graph that maintains topological relationships between its constituent elements—nodes, edges, and triangles.
Point, polyline, and polygon features can be incorporated into a TIN. The vertices are used as nodes, which are connected by edges that form triangles. Edges connect nodes that are close to one another. The partitioning of continuous space into triangular facets facilitates surface modeling because a very close approximation of a surface can be made by fitting triangles to planar or near planar patches on the surface. Input vector data are incorporated directly in the model and any resulting query or analysis honors them. Since the triangulation is based on proximity, interpolation neighborhoods are always comprised of the closest input data and samples. Proximity based connectivity is also useful for other analysis. For example, Thiessen polygons, also known as Voronoi diagrams, are constructed from TINs.
Certain licensing issues apply when working with TINs. Creation, editing, and analysis functions require a 3D Analyst license while simple data managment, such as copy, delete, and rename only require a core license. Additionally, the use of TIN layers for simple display and query only requires a core license.
TINs can be in-memory only objects or persisted to disk as datasets. A TIN can be made from scratch in memory, have data added, analysis performed, and be discarded without being written to disk. This is helpful when using TIN as a temporary data structure to handle an analysis problem because the expense of writing to disk can be avoided. On the other hand, TINs are often created and saved to disk for use at a later time. The most common example of this is the use of TIN as a surface model that will be used repeatedly over time.
The following code example opens an existing TIN on disk via the TinWorkspace object:
[Java]
static Tin openTin(String dir, String name)throws Exception{
    TinWorkspaceFactory tinFactory = new TinWorkspaceFactory();
    if (tinFactory.isWorkspace(dir)){
        ITinWorkspace tinWorkspace = (ITinWorkspace)tinFactory.openFromFile(dir, 0);
        if (tinWorkspace.isTin(name)){
            Tin tin = (Tin)tinWorkspace.openTin(name);
            return tin;
        }
    }
    return null;
}
The following code example shows an alternate way to open an existing TIN on disk via the TIN object:
[Java]
static Tin openTin1(String dir, String name)throws Exception{
    Tin tin = new Tin();
    tin.init(dir + "/" + name);
    return tin;
}
Several notable interfaces implemented by the TIN object are ITinAdvanced2, ITinEdit, and ISurface:
Triangle, edges, and nodes are the basic elements that comprise a TIN. For advanced TIN editing and analysis you'll need access to these elements and relationships. The TIN subsystem includes TinTriangle, TinEdge, and TinNode objects for this purpose and helper objects, such as TinElementEnumerators and TinFilters that support iterative processing. The filters control which elements are passed through the enumerators.
There's an enumerator for each TIN element type: TinNodeEnumerator, TinEdgeEnumerator, and TinTriangleEnumerator. A variety of filters can be used with the enumerators. The following are the available TIN filters:
The existing filters provide a lot of capability. Additionally, it's relatively easy to program custom filters. This accommodates the specialized requirements of any application.
TinPolyline and TinPolygon helper objects are used to access logical polyline and polygon features in a TIN for the sake of conversion or analysis. A TinPolyline or TinPolygon is discovered dynamically by starting with a seed element (that is, edge or triangle) and interactively flooding outward to all coincident elements that share a given property of interest. For example, you can extract polygons representing areas of like slope given a seed triangle for each area and a filter that defines the slope range. These helper objects enable you to construct and access complex entities in a TIN based on any user-defined criteria.

Data transfer

The data transfer subsystem contains objects for copying and converting data into and out of geodatabases. See the following illustration showing data conversion objects:

The two central data converter objects are FeatureDataConverter and GeoDBDataTransfer.
FeatureDataConverter will be familiar to users of ArcCatalog; the import facilities make extensive use of this coclass.
GeoDBDataTransfer will also be familiar to users of ArcCatalog; the copy and paste functionality to copy datasets between geodatabases makes use of this class.
Some other objects and interfaces are useful in support of FeatureDataConverter and GeoDBDataTransfer and perform the following functions:
The IFeatureDataConverter interface provides methods to convert data between different formats.
The following code example shows conversion of a feature class to a new feature class in a workspace:
[Java]
static void convertFeatureClass(FeatureClass fclass, Workspace workspace)throws
    Exception{
    FeatureClassName fcName = (FeatureClassName)fclass.getFullName();
    WorkspaceName wkspsName = (WorkspaceName)workspace.getFullName();
    FeatureClassName newFcName = new FeatureClassName();
    newFcName.setName("NewFeatClass1");
    newFcName.setWorkspaceNameByRef(wkspsName);
    FieldChecker fldChecker = new FieldChecker();
    fldChecker.setInputWorkspace(fclass.getWorkspace());
    fldChecker.setValidateWorkspaceByRef(workspace);
    Fields[] outFlds = new Fields[1];
    fldChecker.validate(fclass.getFields(), null, outFlds);
    FeatureDataConverter converter = new FeatureDataConverter();
    converter.convertFeatureClass(fcName, null, null, newFcName, null, outFlds[0], 
        "", 100, 0);
}
The ConvertFeatureDataset method can import whole feature datasets. When using ConvertFeatureClass and ConvertFeatureDataset, if you specify nothing for the OutputGeometryDef parameter, the spatial reference will be taken from the input data or the destination feature dataset, and default spatial index data will be created. The InputQueryFilter parameter allows you to import a subset of the input data.
EnumInvalidObject is a standard enumerator like many others in ArcObjects. It represents a set of objects that failed a data conversion process.
The IEnumInvalidObject interface lets you step through the objects that failed conversion and gain access to InvalidObjectInfo.
InvalidObjectInfo tells you why a particular row or feature could not be loaded.
The IInvalidObjectInfo interface returns information about an object that could not be loaded. One example of ErrorDescription is: The coordinates or measures are out of bounds.
The InvalidObjectID will be –1 unless the source data is in a geodatabase.
A FieldChecker object is used to validate a Fields collection (usually used in conjunction with FeatureDataConverter).
FieldChecker is useful when you are creating a new feature class based on an existing feature class and the input and output data are in different formats. For example, a shapefile field name of UID would be invalid in an Oracle geodatabase since it is a reserved word in that database.
As well as reporting the problems it finds, FieldChecker also generates a new Fields collection with standard fixes for the field name problems. In the previous example, a new field name of UID_ would be generated. The kinds of errors that the field checker detects are listed by esriFieldNameErrorType. See the following illustration:
When converting to a geodatabase, the field checker renames geometry fields to Shape and object ID fields to OBJECTID. No field errors are returned in this situation.
The IFieldChecker interface validates field names and table names relative to a particular workspace.
If you do not set ValidateWorkspace and InputWorkspace before validating the fields, FieldChecker assumes a default set of reserved words and invalid characters. This may cause you to rename fields unnecessarily if the problem does not apply to the data format to which you are converting.
The ValidateTableName method checks a proposed table name against reserved words and invalid characters. It will not verify the table name is already being used in the workspace.
EnumFieldError is a standard enumerator like many others in ArcObjects. It represents a set of field names that could cause problems in a data-conversion process.
The IEnumFieldError interface steps through the field errors found by the field checker. Each element returned is a FieldError object.
A FieldError object provides information about a problem with a field. The IFieldError interface indicates the type of error found and to what field it applies.

Distributed geodatabase

The distributed geodatabase objects are for working with checkout information for active check outs in a geodatabase. It consists of the Replica, ReplicaDataset, and ReplicaDescription objects, which act as specifications for a geodatabase checkout. The ReplicaDescription object is also used for defining data to check out or extract. See the following illustration:
See the GeodatabaseDistributed library for information about objects to create checkouts, and objects for checking in checking out database changes.

Versioning

Versioning allows multiple users to edit spatial and tabular data simultaneously in a long transaction environment. Users can directly modify the database without having to extract data or lock features in advance. The object model provides functionality to create and administer versions, register and unregister classes as versioned, detect differences between versions, and reconcile and post versions. See the following illustration showing versioning objects:
A VersionedWorkspace is a workspace that supports multiuser editing and multiple representations of features classes and tables in a relational database system. VersionedWorkspaces support the IVersionedWorkspace interface. See the following illustration:
A list of all versions to which the user has permissions can be retrieved using the Versions property. The versions returned are owned by the connected user or have public access.
The DefaultVersion property can be used to retrieve the default version of the database. There is always a default version owned by the ArcSDE user.
Versions returns an enumeration of all public versions and those owned by the connected user.
The FindVersion method can be used to retrieve other versions by name. Version names are case-sensitive and limited to 32-characters. Versioned workspace compression is available using the Compress method. Compressing a VersionedWorkspace removes database states not referenced by a version. Only the ArcSDE administrator user can execute the Compress method.
FindVersion finds a specific version given its name. The IVersion interface is used to manage the properties of a version as well as create new versions. Creating a new version requires an existing version to be the parent of the new version. When the new version is created, the parent and child versions are identical.
The following code example updates the SetAccess property of the version associated with the first layer in the map:
[Java]
VersionedWorkspace wksps = new VersionedWorkspace(sdeWorkspaceFactory.open(pset, 0));
if (wksps.getVersionInfo().isOwner()){
    wksps.setAccess(esriVersionAccess.esriVersionAccessPublic);
}
The IVersionEdit interface is used to reconcile a version with a target version. Once reconciled, the object provides the ability to work with representations of the version prior to start editing, the prereconcile version, the reconcile version, and the common ancestor version. The common ancestor version represents the state of the database when the start editing version was originally created from the reconcile version (at the time when each version was identical).
You can only post a version that has been reconciled with any of its ancestor versions. You are not limited to reconciling a version with its immediate parent version. Once you have performed the reconcile, the CanPost method returns true. If you perform an undo operation, CanPost becomes false.
GetCommonAncestorVersion returns the common ancestor version of this version and the reconcile version.
GetConflictClasses returns an enumeration of all classes containing conflicts.
GetModifiedClasses returns an enumeration of all the classes modified in the version.
GetPreReconcileVersion returns the version prior to reconciliation. GetReconcileVersion returns the version against the version currently reconciling.
GetStartEditingVersion returns the version before any edits are made. CanPost returns a Boolean if the version can be posted to the reconcile version.
Post applies the changes in the current version to the reconciled version. Reconcile merges the current edit version with a target version.
The following code example shows how an application can reconcile the current version with the default version. If conflicts are detected, the user will have to interactively perform conflict resolution. If not, the application verifies that it can perform the post operation, then perform the post.
[Java]
boolean conflicts = wksps.reconcile("SDE.DEFAULT");
if (conflicts)
    System.out.println(
        "Conflicts have been detected, review and resolve prior to posting.");
else
    System.out.println(
        "The version has been successful reconciled with the target version, no conflicts were detected.");
if (wksps.canPost())
    wksps.post("SDE.DEFAULT");
Reconcile4 reconciles the current edit version with the specified target version. The target version must be an ancestor of the current version or an error returns. The target version name passed in is case-sensitive and should take the form {owner}.{version_name}—for example, SDE.DEFAULT.
The first Boolean argument specifies if locks should be obtained or not (true acquires the lock, while false does not acquire the locks). Only set this to false if there is no intention of posting changes to default.
The second Boolean argument specifies if the reconcile process should abort the reconcile if conflicts are detected for any class. Ideally, the second Boolean is only set to true when performing a reconcile in a batch type environment where you do not have the ability to interactively resolve conflicts.
The third Boolean argument specifies if the conflicts will be resolved in favor of the child version. In this case, setting the Boolean argument to true takes the child representation over the conflicting changes to the parent.
The forth and final Boolean argument, ColumnLevel, can be used to set the degree of conflict filtering present during a reconcile between versions. Setting this argument to true recognizes conflicts at the attribute and not the row level—for example, if geometry was updated on the target version and a different field was updated on the child—if this argument was set to true, no conflicts are detected.
A conflict class enumerator returns all classes containing conflicts after performing a reconcile. Objects of this type are created through the IVersionEdit.GetConflictClasses property. The enumeration contains a set of IConflictClass objects that specify the conflict classes that were found during the execution of IVersionEdit.Reconcile.
Use IVersionInfo to set the properties of a version (IVersionInfo is a read-only collection of methods used to obtain the different properties of a version). See the following illustration:
The DifferenceCursor returns a cursor of object IDs and IRows based on the difference type used with IVersionedTable.
The set of object IDs returned is dependent on the difference type category. For example, if the difference type DeleteNoChange is applied, the cursor will be empty for the table that has deleted the rows. In this case, the application will have to change the table the version references in the IVersionedTable interface.
The IVersionedObject and IVersionedObject2 interfaces are used to register and unregister feature datasets and classes as versioned. IVersionedObject and IVersionedObject2 also returns the current version that a dataset or table references.
Using the RegisterAsVersioned method on a feature dataset registers all classes in the dataset as versioned. Alternatively, you can use RegisterAsVersioned as an individual feature class. Only the feature dataset or feature class owner can register an object as versioned. The process creates two additional tables in the database.
The IsRegisterAsVersioned method returns a Boolean if the dataset or class is registered in the database as versioned. When called on a feature dataset, if any class is not registered as versioned, false is returned.
The Version method returns the current version the object references. This ensures that the application is working with the correct version of the database.
RegisterAsVersioned provides the ability to register and unregister a feature dataset as versioned. A true value registers the dataset or class as versioned and a false value unregisters the dataset or class as versioned.
IsHasUncompressedEdits returns whether or not there are edits that have not been compressed.
RegisterAsVersioned registers and unregisters a feature dataset as versioned. A true value registers the dataset or class as versioned and a false value unregisters the dataset or class as versioned.
The IVersionedObject3 interface is used to register and unregister classes as versioned with the option on moving edits to base.
Using the RegisterAsVersioned3 method on a feature dataset registers all classes in the dataset as versioned. Alternatively, you can use RegisterAsVersioned3 to register an individual feature class. Only the feature dataset or feature class owner can register an object as versioned. The process creates two additional tables in the database.
The SupportsMovingEditsToBase argument can be used to specify if the class should be registered with the option of moving edits to base. If this property is set to false, the class will be registered but will not move edits to base. This is synonymous with calling IVersionedObject.RegisterAsVersioned(true).
A table in a versioned workspace implements IConflictClass and IVersionedTable.
IConflictClass is obtained from the IEnumConflictClass enumeration. It is provided as a mechanism to work with the conflicting rows from each conflict class after performing a reconcile. If IVersionEdit.Reconcile has not been called prior to this, the classes will not be available. See the following illustration:
The GetDeleteUpdates method returns an ISelectionSet of all the object IDs of rows that have been deleted in the edit version and updated in the target reconcile version. If no conflicts were detected, the selection set is null. IsHasConflicts returns a Boolean if the reconcile detects conflicts.
The GetUpdateDeletes method returns an ISelectionSet of all the object IDs of rows that have been updated in the edit version and deleted in the target reconcile version. If no conflicts were detected, the selection set is null.
The GetUpdateUpdates method returns an ISelectionSet of all the object IDs of rows that have been updated in the edit version and updated in the target reconcile version. If no conflicts were detected, the selection set is null.
The IVersionedTable interface can be used to detect the different conflict categories without performing an IVersionEdit.Reconcile. By specifying the appropriate esriDifferenceType, such as TypeDeleteUpdate or TypeInsert, an IDifferenceCursor is returned with a set of OIDs and IRows for differences. See the following illustration:
Differences returns a cursor that can be used to retrieve the rows by the difference type. See the following illustration:

Archiving

Working with historical data allows you to access information about previous versions of the data. Archiving provides the ability to store all temporal representations of a dataset, writing any changes made to an object to an associated archive table. This object model provides functionality to create historical versions that reference a specific moment. Since this version represents a specific moment, any queries against it represents the view of the dataset at that particular moment. See the following illustration:
A class to participate in archiving must be archiving enabled. This can be achieved through the IArchivableObject interface. Before enabling archiving on a class, check if the archive is already archiving through the IsArchiving property. The EnableArchiving property enables archiving on a versioned object. The IArchiveRegistrationInfo interface can be used to create a set of archive table names to be used in the enabling process. Conversely, the DisableArchiving method can be used to disable archiving on a class. The DeleteArchive argument is used to specify whether the archive tables should be preserved as temporal tables in the database.
As mention in the preceding paragraph, if a class is archiving enabled then it is considered an IArchivableClass. By registering a object for archiving, an archive table is created and an association between this table and the object class is made. It is for this reason that IArchivableClass is an optional interface supported by an ObjectClass. This interface has the Archive property that returns a pointer to the archive table associated with the archivable class.
IHistoricalWorkspace is an optional interface supported by a workspace. This interface provides functionality to add and remove historical markers, which are named moments in time. An enumeration of historical markers present on the workspace can also be instantiated through the HistoricalMarkers property on this interface. The FindHistoricalVersionByName and FindHistoricalVersionByTimeStamp methods should be used to retrieve other historical versions that are present on the workspace.
The IHistoricalVersion interface is used to manage the properties of a historical version. This interface has one property, GetTimeStamp, which corresponds to the particular moment in time the historical version references.
A named historical version is essentially a HistoricalVersionMarker. They can be created using the AddHistoricalMarker method and exist on the workspace like transactional versions. The IHistoricalMarker interface, which is supported by HistoricalVersionMarker provides access to the properties of historical markers through the GetName and GetTimeStamp properties.
The following code example shows how to loop through the historical markers on a workspace:
[Java]
IHistoricalWorkspace historicalWksps = new IHistoricalWorkspaceProxy(workspace);
IEnumHistoricalMarker enumHM = historicalWksps.getHistoricalMarkers();
IHistoricalMarker marker = enumHM.next();
while (marker != null){
    System.out.println("Name: " + marker.getName() + "Time Referenced: " +
        marker.getTimeStamp());
    ;
    marker = enumHM.next();
}

Name objects

A name object is a persistable software object that identifies and locates a geodatabase object, such as a dataset, workspace, or a map object, such as a layer. See the following illustration:
A name object supports an open method that allows the client to get an instance of the object (for example, the dataset or workspace) given the name object. A name object acts as a moniker that supports binding to the named object.
The geodatabase supports methods on workspaces that hand out name objects that can be used by browsing clients to display the names of datasets in the workspace and to instantiate any specific dataset. Name objects can also carry properties that describe the object being named. A browsing client can use these properties to display additional information about the object being named. A name object can also support methods to access metadata or methods to change permissions on the object. In these cases, a name object can be used as a lightweight surrogate of the object until further properties of the object are needed or additional methods on the object need to be called.
Name objects are cocreatable and can also be used to specify datasets that have yet to be created—for example, the output dataset to be created by a geoprocessing operation.
There are several kinds of name objects—for example, workspace, table, feature class, feature dataset, raster, and relationship class name objects.
A WorkspaceName is a key component of any dataset name for datasets in the workspace. See the following illustration:
The IWorkspaceName interface lets you access the properties of a workspace name. See the following illustration:
To create a new workspace name, set the WorkspaceFactoryProgID property followed by the PathName or ConnectionProperties.
The following code example creates a new workspace name for a personal geodatabase:
[Java]
WorkspaceName wkspsName = new WorkspaceName();
wkspsName.setWorkspaceFactoryProgID("esriDataSourcesGDB.AccessWorkspaceFactory");
wkspsName.setPathName("c:/Data/usa/usa.mdb");
The workspace factories for all the workspaces are in the various DataSources libraries. At the end of the preceding code example, the name object could be referring to an existing workspace or one that needs to be created. If the workspace already exists, it can be opened with IName.Open—effectively, this procedure is equivalent to opening a workspace using Open or OpenFromFile on IWorkspaceFactory. If the workspace does not exist and needs to be created, use IWorkspaceFactory.Create.
In some circumstances, you may have a full workspace object but require a workspace name. See the following code example:
[Java]
AccessWorkspaceFactory accessWorkspaceFactory = new AccessWorkspaceFactory();
Workspace wksps = new Workspace(accessWorkspaceFactory.openFromFile(
    "c:/Data/usa/usa.mdb", 0));
wkspsName = (WorkspaceName)wksps.getFullName();
The Type, Category, WorkspaceFactoryProgID, and BrowseName properties return information on the workspace.
DatasetName is an abstract class that covers name objects for datasets in a workspace. DatasetName objects identify and locate datasets in a workspace. In addition, they may carry additional properties that describe the named dataset. See the following illustration:
DatasetName objects support methods to access metadata for the named object (via the optional IMetadata interface) and to manage privileges for the dataset (via the ISQLPrivileges interface). The DatasetName object for any existing dataset can be obtained by reading the IDataset.GetFullName property. DatasetName objects can also be created to specify new datasets that are to be created by an operation.
The IDatasetName interface provides access to the basic properties of a dataset name object. See the following illustration:
The Name property returns the identifier for the dataset within the context of its workspace. The value of the Name property of the dataset name object (IDatasetName.GetName) is the same as the value of the name property for the dataset (IDataset.GetName).
The WorkspaceName property returns the workspace name object for the workspace containing the dataset being specified by the dataset name object.
You can use the IDataset.GetFullName interface to get a dataset name object from the dataset object.
The following code example goes from a feature class to a feature class name:
[Java]
FeatureClass fclass = new FeatureClass(wksps.openFeatureClass("states"));
FeatureClassName fclassName = (FeatureClassName)fclass.getFullName();
A dataset name can also refer to a dataset that does not exist. This is useful when creating new data, for example, with feature data converters.
The following code example creates a new workspace name:
[Java]
WorkspaceName wkspaseName = new WorkspaceName();
wkspaseName.setWorkspaceFactoryProgID("esriDataSourcesGDB.AccessWorkspaceFactory");
wkspaseName.setPathName("c:/Data/usa/usa.mdb");
The ISQLPrivilege optional interface provides information about the permissions you have on a database object and provides information on how to change the permissions for other users. It only applies to datasets that are stored in a multiuser SQL environment, most typically, an ArcSDE geodatabase. ISQLPrivilege controls access to database objects. See the following illustration:
The esriSQLPrivilege enumeration defines values that can be used with ISQLPrivilege. The bitwise OR operation can be applied to the values if more than one privilege applies (equal to summing the integer values). For example, if the SQLPrivileges property returns a value of 9, you have select and delete permission on the dataset but not insert or update. A value of 15 indicates full privileges. See the following illustration:
The following code example grants select and update privileges to a user (Scott). The dataset name can be a feature dataset, in which case, Scott receives the privileges on all the contents of the feature dataset.
[Java]
FeatureDatasetName fdtstName = new FeatureDatasetName();
fdtstName.setName("Land_use");
fdtstName.setWorkspaceNameByRef(wkspaseName);

ISQLPrivilege sqlPriv = new ISQLPrivilegeProxy(fdtstName);
sqlPriv.grant("Scott", esriSQLPrivilege.esriSelectPrivilege +
    esriSQLPrivilege.esriUpdatePrivilege, false);
The following are types of DatasetName objects in the geodatabase:

Relationship query table

The relationship query table subsystem contains objects for working with on-the-fly table joins (RelQueryTable) and memory relationships (MemoryRelationshipClass). See the following illustration showing on-the-fly table join objects:
A MemoryRelationshipClassFactory is an object that manages the memory relationship classes that exist in an application. You must use a MemoryRelationshipClassFactory or a MemoryRelationshipClassName object to create new memory relationship classes. Like workspace factory objects, a MemoryRelationshipClassFactory is a singleton object (you can have only one instance of this object in a process).
The IMemoryRelationshipClassFactory interface provides an Open method that creates a new MemoryRelationshipClass. See the following illustration:
A MemoryRelationshipClass is a simple (noncomposite), nonattributed RelationshipClass that does not support relationship rules.
A MemoryRelationshipClass inherits from a RelationshipClass and although it implements the same interfaces, not all properties and methods are supported. The following section reviews each of these interfaces and describes which properties and methods behave differently or are not supported with memory relationship classes.
The IRelationshipClass interface provides information on how the relationship class was defined—functionality to create and delete individual relationships—and methods to find related objects.
The properties and methods of IRelationshipClass that are not shown in the following illustration behave the same way with memory relationship classes as they do with other relationship classes:
The following code example creates a MemoryRelationshipClass between the us_states feature class and the us_counties feature class. The MemoryRelationshipClass is used to print the counties that appear in the state of California.
[Java]
SdeWorkspaceFactory sdeWorkspaceFactory = new SdeWorkspaceFactory();
PropertySet pset = new PropertySet();
pset.setProperty("SERVER", "zinc");
pset.setProperty("INSTANCE", "9192");
pset.setProperty("USER", "gdb");
pset.setProperty("PASSWORD", "gdb");
pset.setProperty("VERSION", "sde.DEFAULT");
Workspace featureWksp = new Workspace(sdeWorkspaceFactory.open(pset, 0));

FeatureClass fclass = new FeatureClass(featureWksp.openFeatureClass("GDB.States"));
FeatureClass fclass2 = new FeatureClass(featureWksp.openFeatureClass("GDB.Cities"));

QueryFilter qfilter = new QueryFilter();
qfilter.setWhereClause("STATE_NAME = 'California'");
FeatureCursor fcursor = new FeatureCursor(fclass.search(qfilter, false));
Feature feature = (Feature)fcursor.nextFeature();
System.out.println(feature.getFields().getField(2).getName());
System.out.println(feature.getValue(2));

MemoryRelationshipClassFactory factory = new MemoryRelationshipClassFactory();
MemoryRelationshipClass rclass = (MemoryRelationshipClass)factory.open("test",
    fclass, "STATE_NAME", fclass2, "STATE_NAME", "forward", "backward",
    esriRelCardinality.esriRelCardinalityOneToMany);

Set relateSet = (Set)rclass.getObjectsRelatedToObject(feature);
Object rbuf = relateSet.next();
while (rbuf != null){
    System.out.println(new Feature(rbuf).getValue(2));
    rbuf = relateSet.next();
}
RelQueryTableFactory is an object that manages the RelQueryTables in the application. Use a RelQueryTableFactory or a RelQueryTableName object to create new RelQueryTables.
Like the workspace factory objects, a RelQueryTableFactory is a singleton object (you can only have one instance of this object in a process). See the following illustration showing IRelQueryTableFactory:
The IRelQueryTableFactory interface provides an Open method to define the data a RelQueryTable represents and how that data is accessed. The following illustration shows the meaning of each of the input parameters:
 
A RelationshipClass is used when creating a RelQueryTable to specify the tables involved and the fields on which the join is based. The RelationshipClass can be stored in a geodatabase or created in memory. Memory relationship classes can include tables that belong to different data sources. Therefore, a RelQueryTable can join tables from different data sources. See the following illustration:
A RelQueryTable includes a source table or feature class and a destination table or feature class. If you step through a cursor opened from a RelQueryTable, each row includes the columns from both input tables. The fields from the source display on the left and the fields from the destination display on the right. Each row from the table is composed of the primary and foreign keys from IRelationshipClass to produce a single row.
Shapes can only be retrieved from the source table. If the destination table has a geometry field, it will not be included in the RelQueryTable.
When you perform a join in ArcMap, a RelQueryTable object is created and used as the table or layer's data source for all display purposes. In ArcMap, use the IDisplayTable.GetDisplayTable property to get a joined table or layer's RelQueryTable. See the following illustration that shows the results of joining two feature classes:
Since a RelQueryTable implements IObjectClass and IFeatureClass and inherits from Table, it can be treated like any other table or feature class. The IFeatureClass interface is implemented only when the source is a feature class. A RelQueryTable cursor is read-only; therefore, edit the source and destination to change the data.
A RelQueryTable is designed to work with relationships that have one-to-one or many-to-one cardinality. If the cardinality is one-to-many, a row from the source will be associated with the first matching row in the destination—any other matching rows are ignored. A RelationshipClass with a many-to-many cardinality is not supported and results in an error. If the relationship has a cardinality of one-to-many or many-to-many, use RelationshipClass objects to access the data. If the cardinality is one-to-one but the relationship is defined as one-to-many, the RelQueryTable still processes correctly.
A RelQueryTable will have an ObjectID if the source has an ObjectID. When initialized, the RelQueryTable uses the values from the source's ObjectID field to define its ObjectIDs. If the source is not an ObjectID object class, the RelQueryTable can still access the data, but there will be limitations, such as an inability to select rows.
By definition, ObjectIDs must be unique. The reason relationships with one-to-many cardinality match one row from the source to only one row in the destination is to prevent repeating ObjectIDs in the RelQueryTable. Repeating ObjectIDs will cause many objects, such as SelectionSets and table windows, to behave incorrectly.
The IRelQueryTableManage interface provides an Init method to define what data a RelQueryTable represents and how that data is accessed. See the following illustration:
The following code example uses a MemoryRelationshipClass and a RelQueryTable to join country demographic data to a country's feature class and print the field names:
[Java]
RelQueryTableFactory relQueryTableFact = new RelQueryTableFactory();
RelQueryTable relQueryTab = (RelQueryTable)relQueryTableFact.open(rclass, true, null,
    null, "", true, true);

Cursor cursor = new Cursor(relQueryTab.search(null, true));
Fields flds = (Fields)cursor.getFields();
for (int i = 0; i < flds.getFieldCount(); i++){
    Field fld = (Field)flds.getField(i);
    System.out.println(fld.getName());
}
The IRelQueryTable interface gets the source and destination and the RelationshipClass or MemoryRelationshipClass used to define the RelQueryTable. The source and destination can be tables, feature classes, or other RelQueryTables. See the following illustration:
For example, if you want to join two tables to a feature class, create RelQueryTableA to join one of the tables to the feature class, then create RelQueryTableB to join the second table to RelQueryTableA. RelQueryTableA is the source for RelQueryTableB. See the following illustration:
 
The following code example shows how to step through a RelQueryTable's source and destination and prints the names of the joined tables and feature classes. This printed list is similar to the list of joined tables and feature classes in the Joins and Relates tab on the Layer or Table Properties dialog boxes in ArcMap.
[Java]
System.out.println("The joined tables include:");
ITable pTable = relQueryTab;
while (pTable instanceof IRelQueryTable){
    relQueryTab = (RelQueryTable)pTable;
    ITable destTable = relQueryTab.getDestinationTable();
    IDataset destTableIDataset = new IDatasetProxy(destTable);
    System.out.println(destTableIDataset.getName());
    pTable = relQueryTab.getSourceTable();
}

System.out.println(new IDatasetProxy(pTable).getName());
A RelQueryCursor is created when you open a cursor on a RelQueryTable. Use methods, such as Search, from ITable and IFeatureClass to open the cursor. Since it inherits from Cursor, it implements ICursor and IFeatureCursor if the RelQueryTable has geometry. See the following illustration:
A RelQueryCursor is read-only; therefore, performing edits using the IRow.Delete and IRow.Store methods is not supported. Also, trying to open an insert or update cursor results in an error since there is no insert or update RelQueryCursor. The ICursor interface provides access to a set of rows.
The following illustration shows how ICursor's properties and methods behave when used on a RelQueryCursor:
 
A RelQueryRow can be obtained from a cursor (ICursor.NextRow) or methods, such as ITable.GetRow. The ITable.CreateRow method is not supported and returns an error if used.
A MemoryRelationshipClassName object is a representation of a MemoryRelationshipClass object. A MemoryRelationshipClassName can be used to create new, work with existing, or persist MemoryRelationshipClasses. See the following illustration:
The IMemoryRelationshipClassName interface contains properties that correspond to the parameters used with the IMemoryRelationshipClassFactory.Open method. These include the Origin and Destination tables, fields, and the forward and backward path names. See the following illustration:
The only parameters from the IMemoryRelationshipClassFactory.Open method that don't have a corresponding property in IMemoryRelationshipClassName are the name and cardinality. Use IDatasetName to set the name and IRelationshipClassName to set the cardinality. Both of these interfaces are inherited by MemoryRelationshipClassName.
When creating a new MemoryRelationshipClass using a MemoryRelationshipClassName object, only the properties previously described need to be set.
The following code example creates a MemoryRelationshipClass from a MemoryRelationshipClassName:
[Java]
MemoryRelationshipClassName mrcname = new MemoryRelationshipClassName();
IName originName = (new FeatureClass(featureWksp.openFeatureClass("GDB.States")))
    .getFullName();
IName destinationName = (new FeatureClass(featureWksp.openFeatureClass("GDB.Cities"))
    ).getFullName();
mrcname.setOriginNameByRef(originName);
mrcname.setDestinationNameByRef(destinationName);
mrcname.setOriginPrimaryKey("STATE_FIPS");
mrcname.setOriginForeignKey("STATE_FIPS");
mrcname.setForwardPathLabel("forward");
mrcname.setBackwardPathLabel("backward");

mrcname.setCardinality(esriRelCardinality.esriRelCardinalityOneToOne);
mrcname.setName("New_MemRC");

MemoryRelationshipClass mrclass = new MemoryRelationshipClass(mrcname.open()); 
    // TODO should work - (MemoryRelationshipClass) mrcname.open();
A RelQueryTableName is a representation of a RelQueryTable. A RelQueryTableName can be used to create a RelQueryTable, work with an existing RelQueryTable, or persist a RelQueryTable. See the following illustration:
IRelQueryTableName contains properties that correspond to the parameters used with the IRelQueryTableFactory.Open method previously described. See the following illustration:
The following code example shows how to create a new RelQueryTable from a RelQueryTableName object (the MemoryRelationshipClassName has been created):
[Java]
RelQueryTableName rqtname = new RelQueryTableName();
rqtname.setRelationshipClassNameByRef(mrcname);
rqtname.setForwardDirection(true);
rqtname.setDoNotPushJoinToDB(true);
rqtname.setTargetColumns("");
rqtname.setLeftOuterJoin(true);
rqtname.setSrcQueryFilterByRef(null);
rqtname.setSrcSelectionSetByRef(null);

RelQueryTable rqtable1 = new RelQueryTable(rqtname.open());
Use IDataset.GetFullName on an existing RelQueryTable object to get a corresponding RelQueryTableName object.

Raster

The raster subsystem contains objects for accessing and working with rasters, raster datasets, and raster catalogs. These objects are used for accessing file-based raster data and raster data stored in a geodatabase. See the following illustration showing raster objects:

Raster data access objects

Raster data consists of a rectangular array of equally spaced cells, which taken as a whole represent thematic, spectral, or picture data. Raster data can represent everything from qualities of a land surface, such as elevation or vegetation, to satellite images, scanned maps, and photographs. See the following illustration showing raster data access objects:
ArcGIS supports file-based raster data, such as GRID, TIFF, ERDAS IMAGINE, JPEG, and so on. It also supports raster data in a geodatabase including a personal geodatabase and an ArcSDE geodatabase. Regardless the various data sources, two data types are used to represent raster data—raster dataset and raster catalog. A raster dataset represents an existing dataset stored on disk in a particular raster format or in a geodatabase, while a raster catalog manages a collection of raster datasets as one entity—a special feature class in a geodatabase. A raster dataset consists of one or more raster bands. A raster dataset can contain pyramids, statistics, or a colormap, which are used to provide fast access and better display, and may also contain a raster table.
For raster data, a workspace is a raster workspace (or a directory) for file-based raster data, an Access workspace for raster data in a personal geodatabase, or a database workspace for raster data in an ArcSDE geodatabase.
Open a workspace to access raster data. A workspace cannot be cocreated (must be initiated from workspace factories). The RasterWorkspaceFactory is used to initialize a raster workspace, the AccessWorkspaceFactory is used to initialize an Access workspace, and the SdeWorkspaceFactory is used to initialize a database workspace.
The following code example opens a raster workspace from a given directory:
[Java]
static RasterWorkspace openRasterWorkspace(String path)throws Exception{
    RasterWorkspaceFactory rwkspsFactory = new RasterWorkspaceFactory();
    RasterWorkspace rwksps = (RasterWorkspace)rwkspsFactory.openFromFile(path, 0);
    return rwksps;
}
The following code example opens an Access workspace:
[Java]
static RasterWorkspace openAccessWorkspace(String path)throws Exception{
    AccessWorkspaceFactory acsWkspsFactory = new AccessWorkspaceFactory();
    PropertySet propset = new PropertySet();
    propset.setProperty("database", path);
    RasterWorkspace rwksps = (RasterWorkspace)acsWkspsFactory.open(propset, 0);
    return rwksps;
}
The following code example opens a database workspace by passing the ArcSDE connection information:
[Java]
static Workspace openSDERasterWorkspace(String server, String instance, String dB,
    String user, String passwd, String version)throws Exception{
    PropertySet propset = new PropertySet();
    propset.setProperty("Server", server);
    propset.setProperty("Instance", instance);
    propset.setProperty("Database", dB);
    propset.setProperty("User", user);
    propset.setProperty("Password", passwd);
    propset.setProperty("Version", version);

    SdeWorkspaceFactory sdeWkspsFactory = new SdeWorkspaceFactory();
    Workspace wksp = new Workspace(sdeWkspsFactory.open(propset, 0));
    return wksp;
}
The three interfaces on a workspace object provides access to RasterDataset and RasterCatalog objects. IRasterWorkspace and IRasterWorkspace2 are used to open and create a file-based RasterDataset.
The following code example opens an Imagine file in a given directory:
[Java]
RasterWorkspace rwksps = openRasterWorkspace(
    "C:\\Program Files\\ArcGIS\\java\\samples\\data\\raster");
IRasterDataset rasterDataset = rwksps.openRasterDataset("dem1");
To create a file-based raster dataset, specify the origin, width, and height of the raster dataset besides other required parameters, and a raster dataset with the specified dimension and default pixel values will be created. The default pixel values of the raster dataset can be modified to your requirements by writing pixel blocks to the dataset. See the following code example:
[Java]
RasterWorkspace rwksps1 = openRasterWorkspace("C:\\data");
Point point = new Point();
point.putCoords(0, 0);
IRasterDataset rdataset = rwksps1.createRasterDataset("MyImage.img", "IMAGINE Image",
    point, 200, 100, 1, 1, 1, rstPixelType.PT_UCHAR, new UnknownCoordinateSystem(),
    true);
IRasterWorkspaceEx provides access to RasterDataset and RasterCatalog. IRasterWorkspaceEx accesses (through an Access workspace) a file-based RasterDataset and a RasterCatalog in a personal geodatabase. IRasterWorkspaceEx through a database workspace accesses a database RasterDataset and a RasterCatalog in an ArcSDE geodatabase. See the following illustration:
The following code example opens a raster dataset and a raster catalog from a geodatabase:
[Java]
Workspace wksps = openSDERasterWorkspace("zinc", "9192", "sde91_ora9i", "gdb", "gdb",
    "SDE.DEFAULT");
RasterDataset rdataset1 = new RasterDataset(wksps.openRasterDataset("GDB.AIRPHOTO1"))
    ;
RasterCatalog rcatalog = new RasterCatalog(wksps.openRasterCatalog("GDB.Images"));
Creating a raster dataset in a geodatabase creates an empty raster dataset with no dimension, which is basically a placeholder for an attribute of this raster dataset, such as the number of bands, pixel type, raster field properties, and geometry field properties. Once the empty raster dataset is created, raster pixels can be appended from other raster data by mosaicking.
The following code example creates a raster dataset in geodatabase:
[Java]
RasterStorageDef storageDef = new RasterStorageDef();
storageDef.setCompressionType
    (esriRasterCompressionType.esriRasterCompressionJPEG2000);

RasterDef rdef = new RasterDef();
rdef.setSpatialReferenceByRef(new UnknownCoordinateSystem());

GeometryDef geoDef = new GeometryDef();
geoDef.setSpatialReferenceByRef(new UnknownCoordinateSystem());

RasterDataset rdataset2 = new RasterDataset(wksps.createRasterDataset("mydataset", 1,
    rstPixelType.PT_UCHAR, storageDef, "defaults", rdef, geoDef));

Raster datasets

A RasterDataset object represents a raster dataset stored in a file system or in a geodatabase. A RasterDataset is composed of one or more persistent raster bands. The RasterDataset object performs basic dataset management functions, such as copy, rename, and delete. It can also be used to examine dataset properties including raster format, extent, spatial reference, number of bands, and so on. See the following illustration that shows raster dataset objects:
Use RasterDataset to change properties of the dataset. For example, RasterDataset can be used to change the spatial reference associated with the dataset, manipulate the colormap of the raster dataset, build pyramids (reduced resolution datasets), which improve display performance for large raster datasets, and build statistics, which enhances raster renderering. A RasterDataset object can merge pixels from another raster dataset to the raster dataset object. See the following illustration:
The following code example, assuming that a pRaster (IRaster) and pColormap (IRasterColormap) have been created, alters a dataset's colormap and mosaics pRaster to the raster dataset:
[Java]
RasterDataset rdtst = new RasterDataset(wksps.openRasterDataset("GDB.RASTERDATASET"))
    ;
Raster raster = new Raster(rdtst.createFullRaster()); 
    //Assume there is an instance of raster
RasterColormap colorMap = new RasterColormap(); // and an instance of RasterColorMap.

double[] blueValues = new double[256];
colorMap.setBlueValues(blueValues);

//rdtst.alterColormap(colorMap); 
rdtst.mosaic(raster, 0.5);
A RasterDataset can be saved to another format using ISaveAs. The following code
    saves a raster dataset to an IMAGINE format and to a geodatabase, assuming
    pRasterWs is a raster workspace and pWorkspace is an Access workspace or a
    database workspace. 

//rdtst.saveAs("MyImage.img", wksps, "IMAGINE Image" ); 
rdtst.saveAs("MyRaster", wksps, "SDR");
RasterDataset supports IRasterBandCollection interface, but adding or removing bands
    has no effect on the RasterDataset. The IRasterBandCollection.SaveAs plays the
    same role as ISaveAs.SaveAs. RasterDataset object can be used to initiate a
    Raster or RasterBand object representing other aspect of the data. This code
    example returns the first raster band from a raster dataset: 

RasterBand rband = new RasterBand(rdtst.item(0));
Two methods can be used to create a Raster object from a RasterDataset.
    CreateFullRaster method creates a raster with all the properties from the raster
    dataset, such as, number of bands, width and height of the raster dataset;
while CreateDefaultRaster method creates a raster that has a square cell size and
    contains only three raster bands if the dataset has more than three bands. The
    three bands are the defaultbands used in raster RGB renderer and are determined
    by the settings for defaultraster behavior made on the RasterDefaultsEnv object
    in the Carto library. 

Raster raster1 = new Raster(rdtst.createDefaultRaster())
    ;
raster1 = new Raster(rdtst.createFullRaster());
IRasterWorkspace interface and IRasterWorkspaceEx interface through an Access
    workspace creates a file - based RasterDataset;
while IRasterWorkspaceEx interface through database workspace creates a database
    RasterDataset. A file - based RasterDataset and database RasterDataset work the
    same way except on a few interfaces. For example, ITemporyDataset and
    IWorldFileExport interfaces are not supported by a database RasterDataset and
    IRasterPyramid2 interface is not supported by a file - base RasterDataset.
    Besides accessing through a workspace, RasterDataset can also be retrieved from
    a band in the dataset using the RasterDataset property. To access the
    RasterDataset from a Raster object, access a band from the raster, then obtain a
    reference to the dataset from the band. The following shows this technique: 

rband = new RasterBand(raster1.item(0))
    ;
RasterDataset rdataset3 = new RasterDataset(rband.getRasterDataset());

Raster bands

A RasterBand object represents an existing band of a raster dataset. This band may be the only band in a single-band raster dataset or one band in a multiband raster dataset. The RasterBand object can be accessed from the raster or the raster dataset but, regardless of whether it is derived from the static raster dataset or the transient raster, the raster band always represents a static band of raster data.
The following code example shows how to access a raster band from a Raster or a RasterDataset object:
[Java]
IRasterBandCollection bandCol = rdtst;

// Get the first band of the raster.
RasterBand rband = new RasterBand(bandCol.item(0));
A raster band accessed from a file-based raster dataset is a file-based raster band and a raster band accessed from a database raster dataset is a database raster band. Some interfaces are only supported by a file-based raster band but not by a database raster band.
A raster band contains pixel values in the band. It can also contain statistics, a colormap, histogram, or table, which are accessible through the raster band.
The following code example accesses a raster colormap:
[Java]
RasterColormap colorMap1 = null;
boolean[] hasColormap = new boolean[1];
rband.hasColormap(hasColormap);
if (hasColormap[0])
    colorMap1 = (RasterColormap)rband.getColormap();
RasterBand supports IRawPixel, which allows you to read and write pixels to the band. For a file-based raster band, use AcquireCache before writing pixel blocks to prevent unnecessary pyramid building and enhance performance. A file-based raster band also supports IRasterTransaction, which can be used to manage the transaction of editing pixels.

Raster objects

A Raster object, in contrast to the static RasterDataset and RasterBand objects, is transient in nature and can be modified without affecting the source data. This allows the raster to represent your requirements, as you may specify a projection, extent, and cell size into which the input data will be transformed. This makes the raster useful for performing display or analysis in a coordinate system different from what is stored in the raster dataset on disk. See the following illustration:
Because of the transient nature of the raster, modifications made to this object will be lost when the object is released. Although the Raster object is always transient in nature, associate it with one or more raster bands to provide a source for data to be read through the raster. As such, the raster is most easily understood as a way to provide resampling, projection, and data type conversion from one or more raster bands to a desired output coordinate system. The modified raster can be persisted to another raster dataset on disk or in a geodatabase using ISaveAs or IRasterBandCollection interface.
IRasterProps is an important interface that is used to control the properties of the raster, such as extent, width, height, spatial reference, pixel type, NoData value, and so on.
You can get the cell size of a raster by adjusting the width, height, and extent of the raster. If the height and width are changed, the cell size of the raster recalculates by using the new height and width to divide the current raster extent. In this case, it results in a raster with a cell size that is not square. You can control getting a raster with a square cell size by specifying a precalculated height and width.
The NoData value of a raster is represented as an array of values. This variant array of values has the pixel type of the raster and contains one NoData value for each band. This allows the different bands in the raster to contain a different NoData value. If there is no NoData value in the band, the value in the corresponding member of the array will be empty.
Resampling sometime occurs when the properties of the raster are changed. The resampling method used when reading, can be set using the SetResampleMethod IRaster interface.
The following code example sets a new spatial reference (NewSpatialReference) to the raster and persists to a file, assuming raster is obtained:
[Java]
raster.setResampleMethod(rstResamplingTypes.RSP_BilinearInterpolation);
ISpatialReference newSpatialReference = new UnknownCoordinateSystem();
raster.setSpatialReference(newSpatialReference);
raster.saveAs("MyRaster", wksps, "GRID");
A Raster object can create a PixelBlock and the raster's pixel value can be modified by a pixel filter using IPixelFilterOperation and persists to a raster dataset using SaveAs. The raster's pixel value can also be modified and written to the raster dataset using IRasterEdit.
A raster can be displayed using the RasterLayer object (an object in the Carto library).
Rasters can be created from a raster dataset and obtained from the RasterLayer object in the Carto library. See the following code example:
[Java]
Set pRaster = pRasterLayer.getRaster()
The Raster object can also be cocreated. Cocreating a new raster results in an empty raster that is not useful until one or more bands are placed into the raster, providing data for the raster to read. Creating a new raster and populating it with the necessary bands provides the most flexibility. Any time a band is added or removed from a raster, its default settings for spatial reference, extent, and cell size can be changed, and these default settings will be applied to the raster, if they have not been set by the user. See the following code example:
[Java]
RasterBand rband = null; //Assume there is an instance of RasterBand.
raster.appendBand(rband);

Pixel block objects

A PixelBlock object contains a pixel array that can be read from a raster or a raster band. The PixelBlock object is designed to handle generic pixel arrays from any raster data source. This means it must be able to handle single and multiband data, and support different pixel types. To support different pixel types, the PixelBlock transports pixels in a SafeArray, which has the ability to contain many different data types. To support multiple bands or planes of raster data, the PixelBlock provides a separate array for each band in the raster.
The PixelBlock object can be created from Raster and RasterBand. The size of the pixel block is required when creating a pixel block. Once specified, the pixel block size cannot be changed. To read pixel values to the pixel block, the pixel location (in pixel space) in the raster band where the PixelBlock starts to read needs to be specified. See the following code example:
[Java]
Pnt size = new Pnt();
size.setCoords(512, 512);

// Create the pixel block from a raster.
PixelBlock pixelBlock = (PixelBlock)raster.createPixelBlock(size);

// Create the pixel block from a band.
pixelBlock = (PixelBlock)rband.createPixelBlock(size);

// Define the starting pixel in pixel space to read.
Pnt topLeft = new Pnt();
topLeft.setCoords(0, 0);

// Read the pixel block from a band.
rband.read(topLeft, pixelBlock);
You can get the pixel values from the pixel block, modify the pixel values, and write the pixel block with the modified pixel values to a raster band. If the pixel block is created from a raster, the modified pixel block can be written to raster dataset using IRasterEdit.Write.
The following code example, (continued from the previous code example), writes the modified pixel block to the raster band:
[Java]
rband.write(topLeft, pixelBlock);
For small raster datasets, the pixel block can be the size of the entire dataset—which can usually be held in memory—and the starting pixel to read the pixel block can be (0,0). Larger rasters can be read in smaller pieces by creating a smaller pixel block and reading portions of the raster sequentially.
PixelBlockCursor (or RasterCursor) are the objects that divide a large image into many pixel blocks and reads them one by one. The PixelBlockCursor is an enhanced object in ArcGIS 9.0 that works with reading pixel blocks from large images. You can loop through pixel blocks from a RasterBand or a Raster object. When reading pixel blocks from a raster, the size of the pixel block is automatically optimized by the system according to the different raster formats that the raster is created from and the location of the top-left corner of the next pixel block is returned each time a pixel block is read. Define the size of the pixel block to read pixel blocks from a raster band.

Raster catalogs

RasterCatalog is a new data type in ArcGIS 9.0 and only applies to raster catalogs in geodatabase. The RasterCatalog manages a collection of raster datasets as one entity—a special type of feature class. This special type of feature class has a Name field that stores the name of the raster dataset, a Geometry field that stores the footprint (bounding box) of the raster dataset, and a Raster field that stores pixel values of the raster dataset. It can also contain other fields, such as metadata, and so on. See the following illustration:
The value stored in the Raster field is a RasterValue. A RasterValue contains a RasterDataset and a RasterStorageDef. The Raster field has a spatial reference that is applied to all raster values and is defined using RasterDef. The property of the Geometry field is defined by GeometryDef. The footprints of the raster datasets stored in the Geometry field are automatically managed, populated, and spatially indexed by the geodatabase. It is recommended that the spatial reference of the Raster and Geometry field are the same.
In addition to defining the spatial reference for the raster column, RasterDef also defines how the raster values are managed in the raster catalog. A managed raster catalog stores raster value in the raster catalog, while an unmanaged raster catalog stores only the paths to the raster datasets (the raster datasets reside in file system). A raster catalog in an ArcSDE geodatabase is always managed, a raster catalog in a personal geodatabase can be unmanaged, meaning that the raster datasets in the raster catalog do not reside in the personal geodatabase, but in the file system.
The RasterStorageDef object defines how raster value is stored an ArcSDE geodatabase. You can define the tile size, cell size, and origin of the raster value. You can also define the compression type and the resampling method of pyramid building.
As a subclass of FeatureClass, the RasterCatalog consists of rows. The feature in each row is a RasterCatalogItem, a type of feature. A RasterCatalog operates the same as a FeatureClass when accessing or updating the raster datasets in the RasterCatalog—for example, enumeration of the raster datasets in a RasterCatalog is accomplished by acquiring a standard FeatureCursor on the RasterCatalog. Insert and update can be achieved by an insert cursor or an update cursor.
To create a raster catalog, create an empty raster catalog and add rows that contain raster values to the raster catalog.
The following code example shows how to load a raster dataset to a raster catalog:
[Java]
RasterValue rvalue = new RasterValue();
rvalue.setRasterDatasetByRef(rdtst);

RasterCatalog rcatalog = new RasterCatalog(wksps.openRasterCatalog(
    "RASTER.catalog_vat_1"));

FeatureCursor fcursor = new FeatureCursor(rcatalog.insert(false));
IFeatureBuffer row = rcatalog.createFeatureBuffer();
row.setValue(rcatalog.getRasterFieldIndex(), rvalue);
fcursor.insertRow(row);
The following code example shows how to get the raster dataset stored in the first row in a raster catalog:
[Java]
RasterCatalogItem catalogItem = (RasterCatalogItem)rcatalog.getFeature(1);
IRasterDataset rdataset4 = catalogItem.getRasterDataset();
A RasterCatalog can be displayed using GdbRasterCatalogLayer object (an object in the esriCarto library).

Metadata

The Metadata subsystem contains objects to create, copy, edit, import, export, and synchronize metadata for datasets, maps, layers, geoprocessing tools, and so on. See the following illustration:
Most supported objects in ArcGIS can have metadata. For datasets accessed using an Object Linking and Embedding database (OLE DB), ArcSDE 3, or an SDE for coverages database connection, you cannot create or read metadata that exists. For all other objects, if you have write or edit permissions, ArcCatalog by default creates and updates the metadata automatically when it is viewed on the Metadata tab (not when the properties or content of the dataset are changed). This process is referred to as synchronization; the catalog extracts properties from the dataset, calculates values if necessary, and stores the information in the dataset's metadata.
Metadata is stored in an XML document. For file-based datasets, the XML document resides in an appropriately named XML file on the file system. For example, a shapefile's metadata is stored in a file that has the same name as the shapefile—such as, myShapefile.shp.xml. A coverage's metadata is stored in a metadata.xml file in the coverage directory.
For personal geodatabases, connections to a multiuser geodatabase, and objects stored in any geodatabase, the metadata XML document is stored in a binary large object (BLOB) column in the geodatabase administration table (GDB_Metadata). To manage metadata with ArcObjects, you need basic knowledge of XML and XPath to manipulate the metadata elements.
The following code example shows how to access the metadata for a feature class:
[Java]
FeatureClassName fclassName = (FeatureClassName)fclass.getFullName();
XmlPropertySet propSet = (XmlPropertySet)fclassName.getMetadata();
Use IXmlPropertySet2.GetXML to get the value of a specific metadata element and change the value of the element using SetPropertyX. See the following code example:
[Java]
String info = propSet.getXml("idinfo/descript/abstract");
propSet.setPropertyX("idinfo/descript/abstract", "New Abstract",
    esriXmlPropertyType.esriXPTText, esriXmlSetPropertyAction.esriXSPAAddOrReplace,
    false);
fclassName.setMetadata(propSet);

Network dataset

A network dataset is a collection of junction, edge, and turn elements that are connected together modeling how real life entities are connected. The network dataset is used as the input to the solvers of the Network Analyst objects to solve graph theoretic problems. The junctions, edges, and turns of a network dataset are generated from simple features in network sources. The network dataset contains attributes to represent cost impedances, restrictions, and hierarchy values of the network elements.
Use the NetworkDataset object to access the contents of the network dataset. Its main interface, INetworkDataset, inspects the sources, attributes, and other properties of the network dataset. The INetworkBuild interface makes changes to the source and attribute definitions of the network dataset, and regenerates the elements of the network dataset from its sources.
The INetworkQuery interface allows you to query for specific junction, edge, and turn elements in the network dataset. The INetworkQuery interface is also where you create a NetworkForwardStar object to repeatedly query repeatedly adjacent elements in the network. The NetworkForwardStar is the basic object to traverse a network to solve a graph theoretic problem. INetworkForwardStarSetup allows you to customize the NetworkForwardStar object to limit the elements that get returned during the query based on restrictions, barriers, hierarchy, and backtrack settings.
Once you query for a element in the network, use INetworkElement to access properties of the element, such as the element ID, ID of the source that generated the element, and attribute values for the element. INetworkJunction, INetworkEdge, and INetworkTurn allow access to properties of the element that are specific to a particular element type.
The DENetworkDataset object is the data element representation of a network dataset. Its main interface, IDENetworkDataset, allows access to the network dataset's sources, attributes, and other properties. IDENetworkDataset also allows you to modify the data element; however, changes to the data element are not applied to the network dataset until INetworkBuild.UpdateSchema() is called.
Network source objects describe a network source in the network dataset. Each object implements INetworkSource allowing you to view the properties of that source. The object can implement a source-specific interface, such as IEdgeFeatureSource and IJunctionFeatureSource, which allows you to view and set the connectivity settings for that source.
A source can also have specifications for the fields on the source that generate driving directions. These settings are accessed by INetworkSourceDirections.
INetworkAttribute accesses the properties of a network attribute. For network attributes in geodatabase and shapefile network datasets, the IEvaluatedNetworkAttribute specifies which evaluators are associated with this attribute. An evaluator is an object that determines how the attribute values of a network element are calculated. In ArcGIS, there are three evaluators—NetworkConstantEvaluator, NetworkFieldEvaluator, and NetworkScriptEvaluator.
The NetworkConstantEvaluator assigns a constant attribute value to all elements generated by the given source. The NetworkFieldEvaluator assigns attribute values from the values of a single field on the source feature class or from a mathematical expression involving values from multiple fields. The NetworkScriptEvaluator calculates the attribute value from a script involving the properties of each network element. You can also implement your own evaluators by creating objects that implement INetworkEvaluator and INetworkEvaluatorSetup.