Skip to content

ProConcepts Geodatabase

arcgisprosdk edited this page Mar 1, 2016 · 40 revisions

Functionality that uses the fine-grained Geodatabase API. Geodatabase API functionality is found in ArcGIS.Core.dll. The Geodatabase API is commonly used in conjunction with map exploration, map authoring, and editing.

Language:      C# and Visual Basic
Subject:       Geodatabase
Contributor:   ArcGIS Pro SDK Team <[email protected]>
Organization:  Esri, http://www.esri.com
Date:          02/22/2016
ArcGIS Pro:    1.2
Visual Studio: 2013, 2015

####In this topic

  • [Architecture] (#architecture)
  • Datastore
    • [Geodatabase] (#geodatabase)
    • [FeatureService] (#featureservice)
  • Working with feature data
    • Datasets
      • [Table] (#table)
      • [Feature class] (#feature-class)
      • [Feature dataset] (#feature-dataset)
      • [Relationship class] (#relationship-class)
        • [Relationship classes in a feature service] (#relationship-classes-in-a-feature-service)
      • [Attributed relationship classes] (#attributed-relationship-class)
        • [Attributed relationship classes in a feature service] (#attributed-relationship-classes-in-a-feature-service)
    • Definitions
    • Fields
    • Domains
    • Subtypes
    • [Querying data] (#querying-data)
      • [QueryFilter] (#queryfilter)
      • [Where clause] (#where-clause)
      • [Selection] (#selection)
      • [Search] (#search)
        • [Working with rows and features] (#working-with-rows-and-features)
        • [Recycling] (#recycling)
    • Versioning
    • [Working with relationship classes] (#working-with-relationship-classes)
    • Attachments
      • [Adding attachments] (#adding-attachments)
      • [Accessing attachments] (#accessing-attachments)
      • [Updating attachments] (#updating-attachments)
      • [Deleting attachments] (#deleting-attachments)
  • [Editing datastores] (#editing-datastores)
    • [Editing in addin mode] (#editing-in-addin-mode)
    • [Editing in standalone mode] (#editing-in-standalone-mode)
  • [MCT exclusions] (#mct-exclusions)
  • [Known issues] (#known-issues)

Architecture

  • The [ArcGIS.Core.Data API] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6701.html) is a DML-only (Data Manipulation Language) API. This means that all schema creation and modification operations such as creating tables and feature classes, creating and modifying fields, enabling attachments, and so on, need to be performed using the Geoprocessing API.

  • Almost all of the methods in the ArcGIS.Core.Data API should be called on the MCT. The triple-slash documentation on the methods that need to run on the MCT are specified as such. These method calls should be wrapped inside the QueuedTask.Run call. Failure to do so will result in [ConstructedOnWrongThreadException] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic12.html) being thrown.

  • To determine whether the lock on the file system (in the case of file geodatabases) and active connections (in the case of enterprise geodatabases) should be maintained, the API checks if there are any objects being used. Since this is a pure .NET SDK, the garbage collection disposes of objects that are out of scope. However, as [MSDN] (https://msdn.microsoft.com/en-us/library/ee787088(v=vs.110).aspx#the_managed_heap) explains, "The intrusiveness (frequency and duration) of garbage collections is the result of the volume of allocations and the amount of survived memory on the managed heap." Thus, garbage collection frequency being indeterministic can cause the locks and connections to be released depending on when garbage collection runs. It is advisable to either use using blocks with ArcGIS.Core.Data objects or call Dispose on the objects after processing the data from the objects is complete. If Dispose is not called explicitly, there is no major harm done. The garbage collector will call Dispose before reclaiming memory. This is recommended for users who want maximum control of connections and file system locks.

Datastore

A [datastore] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6816.html) is a container of spatial and non-spatial datasets, such as feature classes, raster datasets, and tables.

In the ArcGIS.Core.Data API, [Datastore] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6816.html) is an abstract class that represents any object that serves as a container for datasets. Currently, only [Geodatabase] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6933.html) inherits from [Datastore] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6816.html) supporting the file geodatabase and enterprise geodatabase Datastore types. In future releases, more classes inheriting from Datastore may be added.

Note: Datastore is an abstraction that is conceptually equivalent to Workspace in the ArcObjects API.

Geodatabase

Conceptually, an ArcGIS geodatabase is a collection of geographic datasets of various types held in a common file system folder, administered by a REST service or a multiuser relational DBMS (such as Oracle, Microsoft SQL Server, PostgreSQL, or IBM DB2). Geodatabases come in many sizes, have varying numbers of users, and can scale from small, single-user databases built on files up to larger workgroup, department, and enterprise geodatabases accessed by many users.

In the ArcGIS.Core.Data API, the [Geodatabase] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6933.html) class represents the native data structure for ArcGIS and is the primary data format used for editing and data management. While ArcGIS works with geographic information in numerous geographic information system (GIS) file formats, it is designed to work with and leverage the capabilities of the geodatabase.

File geodatabases and enterprise geodatabases can be opened using the [Geodatabase] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6933.html) class. Given a path to the file geodatabase or an SDE file, a [Geodatabase] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6933.html) object can be obtained as follows:

ArcGIS.Core.Data.Geodatabase fileGeodatabase = new Geodatabase(@"path\to\the\file\geodatabase");
ArcGIS.Core.Data.Geodatabase enterpriseGeodatabase = new Geodatabase(@"path\to\the\sde\file");

If the details of the connection to the enterprise geodatabase are known, a Geodatabase object can be obtained as follows:

//SQL Server
ArcGIS.Core.Data.ConnectionProperties connectionProperties = new ConnectionProperties
										 {
										   AuthenticationMode = AuthenticationMode.DBMS,
										   DBMS = EnterpriseDatabaseType.SQLServer,
										   Instance = "machineName\\instanceName",
										   Database = "databaseName",
										   User = "username",
										   Password = "Not1234",
										   Version = "dbo.DEFAULT"
										 };
ArcGIS.Core.Data.Geodatabase enterpriseGeodatabase = new Geodatabase(connectionProperties);

Another way of obtaining the geodatabase is through [ArcGIS.Core.Data.Table.GetDatastore()] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6811.html). This returns the [ArcGIS.Core.Data.Datastore] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6816.html) reference. If the underlying datastore is a geodatabase, you can cast it to a Geodatabase to access the Geodatabase interface.

FeatureService

The [FeatureService] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6897.html) class represents a feature service and provides access to the datasets contained in the feature service. The FeatureService constructor takes a [ServiceConnectionProperties] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7467.html) object, which specifies the URL to the feature service and, optionally, the credentials to connect to the feature service. Whether the credentials are required depends on the feature service deployment type.

The three kinds of environments in which feature services can be hosted are as follows:

  • Feature services hosted on ArcGIS Online
  • Feature services hosted on ArcGIS Server federated with Portal for ArcGIS
  • Feature services hosted on ArcGIS Server (without federation)

For feature services hosted on ArcGIS Online, the feature service connection uses the ArcGIS Online credentials with which the user signed in on Pro. In case of feature services hosted on ArcGIS Server federated with Portal for ArcGIS, the credentials must be specified by the user when adding the Portal for ArcGIS connection in Pro. For additional details, see [Add a portal connection] (http://pro.arcgis.com/en/pro-app/help/projects/manage-portal-connections-from-arcgis-pro.htm#GUID-E2EB9576-E70B-4878-9541-E411D9AF56A2).

var serviceConnectionProperties = new ServiceConnectionProperties(new Uri("http://federated-server.com/server/rest/services/Hosted/CampusEditing/FeatureServer"));
FeatureService featureService = new FeatureService(serviceConnectionProperties);

For feature services hosted on an ArcGIS server (which is not federated with portal), the credentials must be passed in by assigning them to the User and Password properties on the ServiceConnectionProperties object

var serviceConnectionProperties = new ServiceConnectionProperties(new Uri("https://non-federated-server.com/arcgis/rest/services/UnitedStatesWest/FeatureServer"))
{
  User = "username",
  Password = "password",
};
FeatureService featureService = new FeatureService(serviceConnectionProperties);

Working with feature data

Datasets

The [Dataset] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6806.html) abstract class represents any entity in ArcGIS Pro that is a meaningful and coherent collection of data. For example, [ArcGIS.Core.Data.Table] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7511.html) inherits from Dataset and represents a collection of data that conforms to a specified schema (for example, each row has the same fields).

The five current classes that represent Dataset entities and inherit from Dataset are described below.

Table

[Tables] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7511.html) are a type of dataset containing zero or more rows with one or more columns (or fields). All rows in a table have the same columns and a single value (or no value) associated with each column.

In the geodatabase, attributes are managed in tables based on the following simple, yet essential, relational data concepts:

  • Tables contain rows.
  • All rows in a table have the same columns.
  • Each column has a data type, such as integer, decimal number, character, or date.
  • A series of relational functions and operators (such as SQL) is available to operate on the tables and their data elements.

In the ArcGIS.Core.Data API, [Table] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7511.html) objects can be obtained in the following ways:

ArcGIS.Core.Data.Table table = geodatabase.OpenDataset<ArcGIS.Core.Data.Table>("TableName");
ArcGIS.Core.Data.Table tableFromAliasName = featureService.OpenDataset<ArcGIS.Core.Data.Table>("TableAlias");
ArcGIS.Core.Data.Table tableFromID = featureService.OpenDataset<ArcGIS.Core.Data.Table>(2);
ArcGIS.Desktop.Mapping.Layer selectedLayer = MapView.Active.GetSelectedLayers()[0];
if (selectedLayer is ArcGIS.Desktop.Mapping.FeatureLayer)
{
    ArcGIS.Core.Data.Table table = (selectedLayer as FeatureLayer).GetTable();
}
ArcGIS.Desktop.Editing.Events.RowChangedEvent.Subscribe(args =>
{
    ArcGIS.Core.Data.Row row = args.Row;
    ArcGIS.Core.Data.Table table = row.GetTable();
}
Feature class

[Feature classes] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6856.html) are homogeneous collections of common features, each having the same spatial representation—such as points, lines, or polygons—and a common set of attribute columns—for example, a line feature class for representing a road centerline. In ArcGIS Pro, the currently supported feature classes that are commonly used in the geodatabase are points, lines, and polygons.

In the following images, points, lines, and polygons are used to represent three datasets for the same area: park and recreation area locations as points, roads as lines, and facility sites as polygons

In the ArcGIS.Core.Data API, the [FeatureClass] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6856.html) class inherits from the [Table] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7511.html) class. Obtaining [FeatureClass] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6856.html) objects is similar to obtaining [Table] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7511.html) objects as shown in the following examples:

ArcGIS.Core.Data.FeatureClass table = geodatabase.OpenDataset<ArcGIS.Core.Data.FeatureClass>("FeatureClassName");
ArcGIS.Core.Data.FeatureClass featureClassFromAliasName = featureService.OpenDataset<ArcGIS.Core.Data.FeatureClass>("LayerAlias");
ArcGIS.Core.Data.FeatureClass featureClassFromID = featureService.OpenDataset<ArcGIS.Core.Data.FeatureClass>(2);
ArcGIS.Desktop.Mapping.Layer selectedLayer = MapView.Active.GetSelectedLayers()[0];
if (selectedLayer is ArcGIS.Desktop.Mapping.FeatureLayer)
{
    ArcGIS.Core.Data.Table table = (selectedLayer as FeatureLayer).GetTable();
    if(table is FeatureClass)
    {
          ArcGIS.Core.Data.FeatureClass featureClass = table as FeatureClass;
    }
}
ArcGIS.Desktop.Editing.Events.RowChangedEvent.Subscribe(args =>
{
    ArcGIS.Core.Data.Row row = args.Row;
    if(row is Feature)
    {
        ArcGIS.Core.Data.FeatureClass featureClass = row.GetTable() as FeatureClass;
    }
}
Opening FeatureClass as a table

You can open a [FeatureClass] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6856.html) using the following code:

ArcGIS.Core.Data.Table table = geodatabase.OpenDataset<ArcGIS.Core.Data.Table>("FeatureClassName");

The table is an ArcGIS.Core.Data.Table reference, but in reality, it's an ArcGIS.Core.Data.FeatureClass object. You could cast the table reference as a FeatureClass, and the cast would work as expected.

Feature dataset

A feature dataset is a collection of related feature classes that share a common coordinate system. Feature datasets are used spatially. Their primary purpose is to organize related feature classes into a common dataset for building a topology, a network dataset, or a terrain dataset. Rather than storing data, it acts as a container for other datasets and maintains the extent of its contained datasets and a common spatial reference.

The [ArcGIS.Core.Data.FeatureDataset] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6880.html) object can only be obtained from the [Geodatabase] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6933.html) object.

ArcGIS.Core.Data.FeatureDataset FeatureDataset = geodatabase.OpenDataset<ArcGIS.Core.Data.FeatureDataset>("FeatureDatasetName");
Relationship class

A GIS integrates information about various types of geographic and non-geographic entities, many of which can be related.

  • Geographic entities can relate to other geographic entities. For example, a building can be associated with a parcel.
  • Geographic entities can relate to non-geographic entities. For example, a parcel of land can be associated with an owner.
  • Non-geographic entities can relate to other non-geographic entities. For example, a parcel owner can be assigned a tax code.

Relationship classes in the geodatabase manage the associations between objects in one dataset (feature class or table) and objects in another. Objects at either end of the relationship can be features with geometry or records in a table.

Relationship classes help validate, and in some cases ensure, referential integrity. For example, the deletion or modification of one feature could delete or alter a related feature. Furthermore, a relationship class is stored in the geodatabase, which makes it accessible to anyone who uses the geodatabase. Relationship classes support the following cardinalities:

  • One-to-one
  • One-to-many
  • Many-to-many

Note: The many-to-many relationship classes are considered attributed relationship classes. They can still be opened as relationship classes, but they can also be opened as attributed relationship classes.

The [ArcGIS.Core.Data.RelationshipClass] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7390.html) object can only be obtained from the [Geodatabase] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6933.html) object.

ArcGIS.Core.Data.RelationshipClass relationshipClass = geodatabase.OpenDataset<ArcGIS.Core.Data.RelationshipClass>("RelClassName");

For more information on working with relationship classes, see [Working with relationship classes] (#working-with-relationship-classes).

Relationship classes in a feature service

Since relationship classes without a backing table are not first class entities in Feature Services, they do not have IDs or aliases assigned to them. Therefore, the only way to open non-attributed relationship classes is to specify the origin and destination layers that are involved in the relationship class.

To open relationship classes in a feature service, the [FeatureService.OpenRelationshipClass] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6910.html) method takes either a pair of integers representing the origin and destination layer IDs or a pair of strings representing layer IDs of the origin and destination layers. The first parameter is the origin layer ID or layer alias and the second parameter is the destination layer ID or the layer alias. The return value is a IReadOnlyList of Relationship class objects, because there could be more than one relationship between the specified layers. Note that the order of the parameters makes a difference as to what relationship classes are returned.

IReadOnlyList<ArcGIS.Core.Data.RelationshipClass> srcToDestRelClasses = featureService.OpenRelationshipClass(0, 2));
IReadOnlyList<ArcGIS.Core.Data.RelationshipClass> destToSrcRelClasses = featureService.OpenRelationshipClass(2, 0)); //Not the same as above
IReadOnlyList<ArcGIS.Core.Data.RelationshipClass> srcToDestAliasRelClasses = featureService.OpenRelationshipClass("sourceLayer", "destinationLayer"));
Attributed relationship classes

Any relationship class—whether simple or composite and of any particular cardinality—can have attributes. Relationship classes with attributes are stored in a table in the database. This table contains at least the foreign key to the origin feature class or table and the foreign key to the destination feature class or table.

An attributed relationship can also contain any other attribute. For example, if you consider an attributed relationship class that relates a feature class that stores water laterals and a feature class that stores hydrants, water lateral objects have their own attributes, and hydrant objects have their own attributes. The relationship class describes which water laterals feed which hydrants. Because you want to store some kind of information about that relationship—such as the type of riser connecting the two—you can store this information as attributes in the relationship class.

In the ArcGIS.Core.Data API, the [AttributedRelationshipClass] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6749.html) class inherits from RelationshipClass. All [RelationshipClasses] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7390.html) that have an intermediate table are treated as attributed relationship classes, regardless of whether or not user-defined attributes exist.

The [ArcGIS.Core.Data.AttributedRelationshipClass] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6749.html) object can only be obtained from the [Geodatabase] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6933.html) object.

ArcGIS.Core.Data.AttributedRelationshipClass attrRelationshipClass = geodatabase.OpenDataset<ArcGIS.Core.Data.AttributedRelationshipClass>("AttrRelClassName");

For more information on working with relationship classes, see [Working with relationship classes] (#working-with-relationship-classes).

Attributed relationship classes in a feature service

Attributed relationship classes have a corresponding table backing them and the tables have IDs associated with them. Thus, to open attributed relationship classes, the OpenDataset method is used with the integer ID or string representation of the ID for the backing table.

ArcGIS.Core.Data.AttributedRelationshipClass attributedRelationshipClass = featureService.OpenDataset<AttributedRelationshipClass>(4));
ArcGIS.Core.Data.AttributedRelationshipClass attributedRelationshipClassForAlias = featureService.OpenDataset<AttributedRelationshipClass>("attributedRelationshipAlias"));

Definitions

[Definition] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6823.html) is a concept that represents the metadata about the dataset. While the dataset provides a way to access the data that it encapsulates, the definition describes the dataset's schema, unique properties associated with it, and so on.

It should be noted that all the classes that inherit from the [ArcGIS.Core.Data.Dataset] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6806.html) abstract class have methods, which are unique behaviors expected from that dataset. However, all the metadata must be accessed via the Definition abstract class.

One of the reasons for separating the metadata into a Definition is that opening a [Definition] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6823.html) is a lightweight operation when compared to opening a dataset. For example, if you only need information regarding Polyline FeatureClasses, getting and filtering definitions is more efficient than opening all the FeatureClasses to do the same.

The classes that inherit from the Definition abstract class are as follows:

The two options for accessing [Definitions] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6823.html) are as follows:

ArcGIS.Core.Data.FeatureDatasetDefinition definition = geodatabase.GetDefinition<FeatureDatasetDefinition>("FeatureDatasetName");
ArcGIS.Desktop.Mapping.Layer selectedLayer = MapView.Active.GetSelectedLayers()[0];
if (selectedLayer is ArcGIS.Desktop.Mapping.FeatureLayer)
{
    using (ArcGIS.Core.Data.Table table = (selectedLayer as FeatureLayer).GetTable())
    {
        ArcGIS.Core.Data.TableDefinition definition = table.GetDefinition();
    }
}

Fields

Tables, feature classes, and attributed relationship classes are composed of fields, which are synonymous with columns. The fields represent the schema of the corresponding dataset.

In ArcGIS.Core.Data, the fields are always returned as a read-only list of [ArcGIS.Core.Data.Field] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6914.html) objects accessible by calling GetFields() on the following objects:

For the same dataset, the collection of fields obtained at the same time from the following sets of objects should be equivalent:

  • TableDefinition, RowCursor, RowBuffer, and Row
  • FeatureClassDefinition, RowCursor, RowBuffer, and Feature
  • AttributedRelationshipClassDefinition and AttributedRelationship

After obtaining the read-only collection, you can use [LINQ] (https://msdn.microsoft.com/en-us/library/bb397926.aspx) to filter the list as shown below:

using (ArcGIS.Core.Data.Geodatabase geodatabase = new Geodatabase("path\\to\\gdb"))
using (ArcGIS.Core.Data.FeatureClass enterpriseFeatureClass = geodatabase.OpenDataset<FeatureClass>("LocalGovernment.GDB.FacilitySite"))
{
  ArcGIS.Core.Data.FeatureClassDefinition facilitySiteDefinition = enterpriseFeatureClass.GetDefinition();
  IReadOnlyList<ArcGIS.Core.Data.Field> fields = facilitySiteDefinition.GetFields();

  IEnumerable<ArcGIS.Core.Data.Field> dateFields = fields.Where(field => field.FieldType == FieldType.Date);
}

Domains

In a geodatabase, you can use rules to enforce different types of constraints on the tables and feature classes. The rules include attribute and relationship rules. Attribute rules are the most common, and they're created using domains. Domains are used to specify permissible values that can be assigned to a field.

The following are the different types of domains in a geodatabase:

  • Coded value—Specifies a list of valid values, each with a string representation.
  • Range domains—Specifies a range of valid values through minimum and maximum numeric values.

In the ArcGIS.Core.Data API, a [Domain] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6838.html) is a first class entity modeled as an abstract class. There are two classes, [RangeDomain] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7376.html) and [CodedValueDomain] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6774.html), that inherit from the [Domain] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6838.html) abstract class. The [Domain] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6838.html) provides access to the Name, FieldType, and Description of the [Domain] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6838.html). [RangeDomain] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7376.html) provides additional access to the Min and Max values. The [CodedValueDomain] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6774.html) provides access to the code-value pairs returned as a C# Generic Sorted List of <object,string> where the key is the code.

Currently, Domains can only be accessed on the [Field] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6914.html) object [GetDomain] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6920.html) method. It returns a Domain reference, which has to be safely cast based on the underlying [Domain] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6838.html) type: [CodedValueDomain] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6774.html) or [RangeDomain] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7376.html). The [GetDomain] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6920.html) method has an optional Subtype parameter. This can be used to obtain the domain assigned for the field corresponding to that subtype value represented by the Subtype object passed in as the argument. If there is no domain assigned for the specified subtype, a null value is returned. If there is no subtype passed in, the domain returned is the default domain for the field. If no domain is assigned to a field, a null value is returned.

In future releases, the ability to get all the Domains at the Geodatabase level may be added.

using (ArcGIS.Core.Data.Geodatabase geodatabase = new Geodatabase("path\\to\\gdb"))
using (ArcGIS.Core.Data.FeatureClass enterpriseFeatureClass = geodatabase.OpenDataset<FeatureClass>("LocalGovernment.GDB.FacilitySite"))
{
  ArcGIS.Core.Data.FeatureClassDefinition facilitySiteDefinition = enterpriseFeatureClass.GetDefinition();
  IReadOnlyList<ArcGIS.Core.Data.Field> fields = facilitySiteDefinition.GetFields();

  ArcGIS.Core.Data.Field doubleField = fields.First(field => field.FieldType == FieldType.Double);

  Domain domain = doubleField.GetDomain();

  if (domain is RangeDomain)
  {
    var rangeDomain = domain as RangeDomain;
    //The reason we can directly call convert to double because the domain was obtained from a double Field
    double minValue = Convert.ToDouble(rangeDomain.GetMinValue());
    double maxValue = Convert.ToDouble(rangeDomain.GetMaxValue());
  }

  if (domain is CodedValueDomain)
  {
    var codedValueDomain = domain as CodedValueDomain;
    SortedList<object, string> codedValuePairs = codedValueDomain.GetCodedValuePairs();
    IEnumerable<KeyValuePair<object, string>> filteredPairs = codedValuePairs.Where(pair => Convert.ToDouble(pair.Key) > 20.0d);
    double code = Convert.ToDouble(codedValueDomain.GetCodedValue("sampleValue"));
    string value = codedValueDomain.GetName(21.45d);
  }
}

Subtypes

[Subtypes] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7504.html) are a way to partition objects in a single table into groups with similar rules and behavior. Although subtypes share a common set of fields, each group can have its own attribute and relationship rules, as well as different default values at creation time. An example of this is parcels of land that are often divided into residential, commercial, and industrial subtypes. Subtypes are defined for a single table or feature class and cannot be shared.

Subtypes for the table and feature class can be obtained via [TableDefinition] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7531.html) and [FeatureClassDefinition] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6866.html). Using the [GetSubtypes] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7549.html) method returns a read-only list of [subtype] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7504.html) objects. Each [subtype] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7504.html) object provides access to the subtype code and the subtype name.

using (ArcGIS.Core.Data.Geodatabase geodatabase = new Geodatabase("path\\to\\gdb"))
using (ArcGIS.Core.Data.FeatureClass enterpriseFeatureClass = geodatabase.OpenDataset<FeatureClass>("Fittings"))
{
  var featureClassDefinition = enterpriseFeatureClass.GetDefinition();
  var bendSubtype = featureClassDefinition.GetSubtypes().First(subtype => subtype.GetName().Equals("BEND"));
  var sleeveSubtype = featureClassDefinition.GetSubtypes().First(subtype => subtype.GetName().Equals("SLEEVE"));

  var typeCodeDescFieldIndex = featureClassDefinition.FindField("TYPE_CODE_DESC");
  ArcGIS.Core.Data.Domain domainForBend = featureClassDefinition.GetFields()[typeCodeDescFieldIndex].GetDomain(bendSubtype);
  string bendDomainName = domainForBend.GetName();
  ArcGIS.Core.Data.Domain domainForSleeve = featureClassDefinition.GetFields()[typeCodeDescFieldIndex].GetDomain(sleeveSubtype);
  string sleeveDomainName = domainForSleeve.GetName();
  ArcGIS.Core.Data.Domain domainForNoSubtype = featureClassDefinition.GetFields()[typeCodeDescFieldIndex].GetDomain();
  string masterDomainName = domainForNoSubtype.GetName();
}

Querying data

The following are the two ways to query data using this API:

  • Selection—Access either the entire list of object IDs or the list object IDs for [rows] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7415.html)/[features] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6846.html) matching a criteria. Selection is typically used for obtaining object IDs that satisfy a criteria so that you can, for example, highlight the features on the map. The advantage of using selection is that it's a lightweight operation compared to getting the entire row. Selection is also helpful for combining multiple disparate selections from the same Table/FeatureClass into a single selection.
  • Search—Used to access not only the object ID, but also values for all or a subset of fields on the Table/FeatureClass. Search is also required when any editing of data has to be performed.
QueryFilter

A query filter is used to restrict the records retrieved from the database during a query (with the QueryFilter.WhereClause property), specify which fields of the query result are populated (with the QueryFilter.SubFields property), order the returned result in a certain order (with the QueryFilter.PostfixClause property), and possibly get only unique/distinct results (using the QueryFilter.PrefixClause property). Query filters are used to create cursors and selections and are common throughout the Geodatabase API.

[ArcGIS.Core.Data.QueryFilter] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7365.html) represents the class for creating a query filter. It is one of the very few objects in the ArcGIS.Core.Data API that is thread-agnostic (that is, you can create a [QueryFilter] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7365.html) on a non-MCT thread).

QueryFilter queryFilter = new QueryFilter();

string whereClause = "OWNER_NAME = 'ADA IAN'";
queryFilter.WhereClause = whereClause;

string prefixClause = "DISTINCT";
queryFilter.PrefixClause = prefixClause;

string postfixClause = "ORDER BY OWNER_NAME";
queryFilter.PostfixClause = postfixClause;

string subFields = "OBJECTID, OWNER_NAME";
queryFilter.SubFields = subFields;

[ArcGIS.Core.Data.SpatialQueryFilter] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7495.html) inherits from [ArcGIS.Core.Data.QueryFilter] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7365.html) and has additional properties to specify the filter geometry and spatial relationship type (using the [ArcGIS.Core.Data.SpatialRelationship] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6716.html) enum) to use for the filter geometry to filter the results

MapPoint minPoint = new MapPointBuilder(-123, 41).ToGeometry();
MapPoint maxPoint = new MapPointBuilder(-121, 43).ToGeometry();
SpatialQueryFilter spatialFilter = new SpatialQueryFilter
{
  WhereClause = "OWNER_NAME = 'ADA IAN'",
  FilterGeometry = new EnvelopeBuilder(minPoint, maxPoint).ToGeometry(),
  SpatialRelationship = SpatialRelationship.Intersects,
};
Where clause

A Where clause is a component of a Structured Query Language (SQL) statement that defines attribute constraints on a query. Where clauses are used as properties by QueryFilter and SpatialQueryFilter. Where clauses can consist of one-to-many expressions, linked by logical connectors (AND and OR). The following is the valid format for a Where clause expression:

operand1 predicate operand2

Operands can consist of a field name from a table, a numeric constant, a character string, a simple arithmetic expression, a function call, or a subquery.

Predicate Meaning Example
= Equals TYPE = 3
<> Is not equal to PROVINCE <> 'NS'
>= Is greater than or equal to POPULATION >= 10000
<= Is less than or equal to AVG_TEMP <= 25
> Is greater than HEIGHT > 10
< Is less than SPD_LIMIT < 65
[NOT] BETWEEN Is between a minimum and maximum value DIAMETER BETWEEN 5 AND 10
[NOT] IN Is in a list or the results of a subquery TYPE IN ('City', 'Town')
[NOT] EXISTS Checks a subquery for results EXISTS (SELECT * FROM PARCELS WHERE TYPE='RES')
[NOT] LIKE Matches a string pattern CITY_NAME LIKE 'Montr_al'
IS [NOT] NULL Is value NULL WEBSITE IS NULL

The following are the two types of wildcards that can be used with the LIKE predicate:

  • Single-character wildcard (underscore, _)
  • Multiple-character wildcard (percent sign, %)

Strings containing single-character wildcards evaluate to true if the wildcard corresponds to a single character in the comparison string, whereas strings containing multiple-character wildcards evaluate to true if the wildcard corresponds with zero-to-many characters in the comparison string.

The following are example statements:

  • 'Belmont' LIKE '%mont' (evaluates to true)
  • 'Belmont' LIKE '%elmont%' (evaluates to true)
  • 'Belmont' LIKE 'Belmont_' (evaluates to false)
  • 'Belmont' LIKE 'Bel_ont' (evaluates to true)
Selection

In the ArcGIS.Core.Data API, to obtain a [Selection] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7455.html), the Select method must be called on the Table/FeatureClass or on a Selection object. The Select method takes the following two parameters:

using (Geodatabase geodatabase = new Geodatabase("path\\to\\sde\\file\\sdefile.sde"))
using (Table enterpriseTable = geodatabase.OpenDataset<Table>("LocalGovernment.GDB.piCIPCost"))
{
  QueryFilter anotherQueryFilter = new QueryFilter { WhereClause = "FLOOR = 1 AND WING = 'E'" };

  // For Selecting all matching entries. SelectionOption.Normal is the default parameter.
  Selection anotherSelection = enterpriseTable.Select(anotherQueryFilter);

  // This can be used to get one record that matches the criteria. No assumptions can be made about which record satisfying the criteria is selected.
  Selection onlyOneSelection = enterpriseTable.Select(anotherQueryFilter, SelectionOption.OnlyOne);

  // This will always be one.
  int singleRecordCount = onlyOneSelection.GetCount();

  // This will always have one record.
  IReadOnlyList<long> listWithOneValue = onlyOneSelection.GetObjectIDs();

  // This can be used to obtain an empty selection, which can be used as a container to combine results from different selections.
  Selection emptySelection = enterpriseTable.Select(anotherQueryFilter, SelectionOption.Empty);
}
Search

Searching a Table or FeatureClass is needed for reading and modifying the data in rows matching the query specified by [ArcGIS.Core.Data.QueryFilter] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7365.html) or [ArcGIS.Core.Data.SpatialQueryFilter] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7495.html).

The result of the search is an [ArcGIS.Core.Data.RowCursor] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7446.html), which has an interface similar to the System.Collections.IEnumerator interface (with the exception of the Reset method). [RowCursor.MoveNext()] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7453.html) returns a Boolean representing whether the last record in the result has been returned. If the result is empty, the first call to [RowCursor.MoveNext()] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7453.html) will return false. Typically, to access all the rows in [RowCursor] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7446.html), MoveNext is used in conjunction with a while loop. If [RowCursor.MoveNext()] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7453.html) is true, [RowCursor.Current] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7454.html) gives the [ArcGIS.Core.Data.Row] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7415.html) reference. The underlying object is [ArcGIS.Core.Data.Row] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7415.html) or [ArcGIS.Core.Data.Feature] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6846.html) for a [Table] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7511.html) or a [FeatureClass] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6856.html) respectively. If the object is really a Feature object, it can be cast to a Feature to access the Shape.

To Search a [Table] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7511.html) or [FeatureClass] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6856.html), you can use the [Search] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7524.html) method, which has the following two parameters:

  • [QueryFilter] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7365.html)—Specifies the filter for fetching the rows matching the filter. The default value is null, and a null value fetches all the rows in the table.
  • Boolean for Recycling—Specifies whether successive rows obtained from the row cursor will use a new memory location for each row or use the same memory location as MoveNext is called. [Recycling] (#recycling) is explained in more detail in later sections.
using (Geodatabase geodatabase = new Geodatabase("path\\to\\sde\\file\\sdefile.sde"))
using (FeatureClass schoolBoundaryFeatureClass = geodatabase.OpenDataset<FeatureClass>("LocalGovernment.GDB.SchoolBoundary"))
{
    // Using a spatial query filter to find all features that have a certain district name and lying within a given Polygon.
    SpatialQueryFilter spatialQueryFilter = new SpatialQueryFilter
    {
        WhereClause = "DISTRCTNAME = 'Indian Prairie School District 204'",
        FilterGeometry = new PolygonBuilder(new List<Coordinate>
                          {
                            new Coordinate(1021880, 1867396),
                            new Coordinate(1028223, 1870705),
                            new Coordinate(1031165, 1866844)
                          }).ToGeometry(),

        SpatialRelationship = SpatialRelationship.Within
    };

    //Without Recycling
    using (RowCursor indianPrairieCursor = schoolBoundaryFeatureClass.Search(spatialQueryFilter, false))
    {
        while (indianPrairieCursor.MoveNext())
        {
            using (Feature feature = (Feature)indianPrairieCursor.Current)
            {
                int nameFieldIndex = spatialSearch.FindField("NAME");
                string districtName = Convert.ToString(feature["DISTRCTNAME"]);
                double area = Convert.ToDouble(feature["SCHOOLAREA"]);
                string name = Convert.ToString(feature[nameFieldIndex]);
                Geometry geometry = feature.GetShape();
            }
        }
    }
}
Working with rows and features

[ArcGIS.Core.Data.Feature] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6846.html) inherits from [ArcGIS.Core.Data.Row] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7415.html) and adds the methods for getting and setting the Shape on the Feature.

On Row (and Feature), there is an [integer-based indexer] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7434.html) and a [string-based indexer] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7435.html) for accessing the attributes of the row. If the index of the field is known, the [integer-based indexer] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7434.html) is used, and the [string-based indexer] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7435.html) is used when the field name is known. The return value is always System.Object and must be cast into the corresponding type based on the field type inferred from the corresponding [Field] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6914.html) object.

To work with geometries, [GetShape()] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6852.html) and [SetShape(Geometry)] http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6854.html) must be used. Something to keep in mind while modifying shapes is that since [Geometry] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7965.html) is an [immutable] (/ArcGIS/arcgis-pro-sdk/wiki/ProConcepts-Geometry#immutable-geometries) object, when you set the Shape to a new geometry, the corresponding Builder needs to be used to [build a new geometry] (/ArcGIS/arcgis-pro-sdk/wiki/ProConcepts-Geometry#building-geometries) (possibly using the existing geometry obtained from Feature.GetShape()).

Recycling

Recycling can be used for better performance while accessing complex and large datasets and is typically used to render the shapes on the map or populate a table in the UI.

To enable recycling, the second parameter to the [Search] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7524.html) is set to true (which is the default parameter value). When using recycling, for successive [Row] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7415.html) references obtained while calling [MoveNext] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7453.html) on the [RowCursor] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7446.html), all references obtained in previous iterations of [MoveNext] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7453.html) will point to the current [Row] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7415.html) the [RowCursor.Current] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7454.html) is referring to. This means that once [MoveNext] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7453.html) is called, the previous row is no longer available.

using (Geodatabase geodatabase = new Geodatabase("path\\to\\sde\\file\\sdefile.sde"))
using (FeatureClass schoolBoundaryFeatureClass = geodatabase.OpenDataset<FeatureClass>("LocalGovernment.GDB.SchoolBoundary"))
{
    QueryFilter queryFilter = new QueryFilter
    {
        WhereClause = "DISTRCTNAME = 'Indian Prairie School District 204'"
    };

    using (RowCursor indianPrairieCursor = schoolBoundaryFeatureClass.Search(queryFilter, true))
    {
      try
      {
        Row row1 = null;
        if(indianPrairieCursor.MoveNext())
          row1 = indianPrairieCursor.Current;
        Row row2 = null;
        if(indianPrairieCursor.MoveNext())
          row2 = indianPrairieCursor.Current;

        // If the code reaches this point,
        // row1 and row2 are referencing the second row object obtained 
        // when the MoveNext was called the second time
      }
      finally
      {
        if(row1 != null)
          row1.Dispose();
        if(row2 != null)
          row2.Dispose();
      }
    }
}

Note: Since geometries are [immutable] (/ArcGIS/arcgis-pro-sdk/wiki/ProConcepts-Geometry#immutable-geometries), they are managed by the .NET Garbage Collector. They are not recyclable in the same sense as Row, which implements IDisposable (recycling expects that the processing for the object is completed before the memory is reclaimed, and this becomes impossible in a multithreaded environment since it can be used concurrently). In future releases, support may be added for recycling geometries.

Versioning

Versioning allows multiple users to edit spatial and tabular data simultaneously in a long transactional environment. Users can directly modify the database without having to extract data or lock features in advance.

The following are the three primary abilities that are provided by the API:

  • Lists all the versions in a geodatabase, including properties of the versions.
  • Connects a specific version.
  • Lists the differences between Tables and FeatureClasses from different versions.

The [VersionManager] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7581.html) object can be accessed from the [Geodatabase] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6933.html) object. [VersionManager] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7581.html) provides access to the currently connected version; a list of historical versions; and a list of all public versions, protected versions, and private versions owned by the currently connected user. It should also be noted that [VersionManager] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7581.html) is only accessible if the [IsVersioningSupported] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6950.html) method on the [Geodatabase] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6933.html) object returns true.

The versions returned are [ArcGIS.Core.Data.Version] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7566.html)objects, which provide access to the following:

  • Attributes such as name, access type, and description
  • Parent Version object
  • List of child Version objects
  • Whether the current user is the owner of the version

To connect to a version represented by a [Version] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7566.html) object obtained from [VersionManager] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7581.html), you can call the [Connect] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7571.html) method on the [Version] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7566.html) object, which returns the corresponding [Geodatabase] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6933.html) object so that datasets in that version of the geodatabase can be obtained.

To find differences, one workflow could be as follows:

  1. Get the Geodatabase object using one of the methods described in [Geodatabase] (#geodatabase).
  2. Use [VersionManager] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7581.html) to find the other Version object of interest.
  3. Get the Geodatabase object for the other version using [Connect()] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7571.html).
  4. Open the corresponding Table/FeatureClasses from both Geodatabase objects.
  5. Get the [DifferenceCursor] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6830.html) using the Differences method.

The type of difference can be specified as a parameter to the [Differences] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7521.html) method using the [ArcGIS.Core.Data.DifferenceType] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6706.html) enum.

using (ArcGIS.Core.Data.Geodatabase geodatabase = new Geodatabase("path\\to\\sde\\file"))
{
  VersionManager versionManager = geodatabase.GetVersionManager();
  var versionList = versionManager.GetVersions();

  //The default version will have a null Parent
  Version defaultVersion = versionList.First(version => version.GetParent() == null);
  
  IEnumerable<Version> publicVersions = versionList.Where(version => version.GetAccessType() == VersionAccessType.Public);
  Version qaVersion = defaultVersion.GetChildren().First(version => version.GetName().Contains("QA"));

  Geodatabase qaVersionGeodatabase = qaVersion.Connect();

  var currentFeatureClass = geodatabase.OpenDataset<FeatureClass>("featureClassName");
  var qaFeatureClass = qaVersionGeodatabase.OpenDataset<FeatureClass>("featureClassName");

  DifferenceCursor differenceCursor = currentFeatureClass.Differences(qaFeatureClass, DifferenceType.DeleteNoChange);
  
  while (differenceCursor.MoveNext())
  {
    //The current row value refers to the row on the source Table/FeatureClass
    //Thus, for DeleteNoChange differences, the row will be null
    Row current = differenceCursor.Current;
    long objectID = differenceCursor.ObjectID;
    //Do something with the object Id
  }
}

Working with relationship classes

The following operations can be performed on [RelationshipClass] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7390.html):

Attachments

Attachments allow you to add files to individual features and can be images, PDFs, text documents, or any other type of file. For example, if you have a feature representing a building, you could use attachments to add multiple photographs of the building taken from several angles, along with PDF files containing the building's deed and tax information.

To add attachments, you first need to enable attachments on the feature class or table. When you enable attachments, a new table is created to contain the attachment files, and a new relationship class is created to relate the features to the attached files.

Since ArcGIS.Core.Data API is a DML only API, one option to enable attachments programmatically is to use the Geoprocessing API.

var parameters = Geoprocessing.MakeValueArray("path\\to\\sde\\connection.sde\\FeatureClassName");
var gpResult = await Geoprocessing.ExecuteToolAsync("management.EnableAttachments", parameters);

Determining whether a table or feature class has attachments enabled can be done using the [IsAttachmentEnabled] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7523.html) property on the Table and FeatureClass objects.

Adding attachments

To add an attachment, a new attachment object can be created using the [Attachment constructor] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6723.html). The Name, ContentType, and Data can be obtained and set using the methods on the new attachment. Once all the information has been set, the [AddAttachment] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7420.html) method on the [Row] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7415.html) can be called with the newly created [Attachment] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6718.html) object to add the attachment. An example of adding attachments can be found at [Adding attachments] (/ArcGIS/arcgis-pro-sdk/wiki/ProSnippets-Geodatabase#adding-attachments).

To set the data on the attachment, a memory stream must be created from the file on disk. One way of accomplishing this is described in [Obtaining a MemoryStream from a file] (/ArcGIS/arcgis-pro-sdk/wiki/ProSnippets-Geodatabase#obtaining-a-memory-stream-to-modify-or-create-attachment-data).

Accessing attachments

To get attachments, the [GetAttachments] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7424.html) method on the Row can be used. If there are no arguments passed in, all the attachments for that row are returned. If there is a list of attachment IDs passed in as the first argument, the attachments matching the IDs are returned. The second argument is a Boolean, which is used to specify whether or not the data of the attachment should be returned. For an example of accessing attachments, see [Updating attachments] (/ArcGIS/arcgis-pro-sdk/wiki/ProSnippets-Geodatabase#updating-attachments).

Updating attachments

After getting the attachments from the row or feature, the getters and setters on the attachments can be used to set the Name, Content Type, and Data. Then, the updated attachment objects can be used to call [UpdateAttachment] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7432.html) on the [Row] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7415.html) or [Feature] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6846.html). For an example of accessing attachments, see [Updating attachments] (/ArcGIS/arcgis-pro-sdk/wiki/ProSnippets-Geodatabase#updating-attachments).

Deleting attachments

To delete an attachment, you need to get the attachment from the row first, and use [DeleteAttachments] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7422.html) on the [Row] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7415.html) or [Feature] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6846.html) by passing in a list of attachment IDs to be deleted. The return value is a dictionary of attachment IDs to the exception thrown when the deletion of the corresponding attachment failed. If the dictionary is empty, the requested attachments were deleted successfully. If no arguments are passed to [DeleteAttachments] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7422.html, all the attachments for that row are deleted. For an example of deleting attachments, see [Deleting attachments] (/ArcGIS/arcgis-pro-sdk/wiki/ProSnippets-Geodatabase#deleting-attachments)

Editing datastores

The ArcGIS.Core.Data API provides support for performing multiple edits as a single transaction (also known as long transactions). The following are the two modes under which editing in a transaction can be accomplished:

  • Editing in addin mode
  • Editing in standalone mode
Editing in add-in mode

This is the normal mode of performing edits in a transaction while authoring add-ins for ArcGIS Pro. The [EditOperation] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic9721.html) class provides the support for editing in a transaction in ArcGIS Pro. For more details, see Performing edits in the ArcGIS Pro documentation.

Editing in stand-alone mode

When the ArcGIS.Core API is used outside ArcGIS Pro (for example, in a console application) using the [ArcGIS.CoreHost] (/ArcGIS/arcgis-pro-sdk/wiki/proconcepts-CoreHost) API support, it is referred to as stand-alone mode. In this mode, when performing edits in a transaction, the [ArcGIS.Core.Data.Geodatabase.ApplyEdits] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6941.html) method should be used.

using (RowCursor rowCursor = featureClass.Search(new QueryFilter {WhereClause = "NAME = 'Kern'"}, false))
{
  if(!rowCursor.MoveNext())
    return;
  Feature firstFeature = null;
  Feature secondFeature = null;
  geodatabase.ApplyEdits(() =>
  {
    rowCursor.Current["NAME"] = "Kern-Another";
    rowCursor.Current.Store();
    RowBuffer rowBuffer = featureClass.CreateRowBuffer();
    rowBuffer[FileGDBPathsAndNames.CountyNameColumn] = "Santa Ana";
    rowBuffer[FileGDBPathsAndNames.StateNameColumn] = "California";
    firstFeature = featureClass.CreateRow(rowBuffer);
    rowBuffer.Dispose();
    rowBuffer = featureClass.CreateRowBuffer();
    rowBuffer[FileGDBPathsAndNames.CountyNameColumn] = "Irvine";
    rowBuffer[FileGDBPathsAndNames.StateNameColumn] = "California";
    secondFeature = featureClass.CreateRow(rowBuffer);
    rowBuffer.Dispose();
  });
  rowCursor.Current.Dispose();
}

As shown in the above example, the ApplyEdits method takes an Action delegate, which encapsulates all the edits that must be performed in a transaction. The transaction is commited only if there are no exceptions thrown during the execution of the Action delegate. If there is any unhandled exception thrown during the execution, all the edits made up to that point are rolled back, and the transaction is aborted.

The following are the differences between how [EditOperation.ExecuteAsync] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic9310.html) and [Geodatabase.ApplyEdits] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic6941.html) work:

  • The ApplyEdits method can only be used to make edits within a single geodatabase, while the ExecuteAsync on the EditOperation allows interleaving edits to multiple geodatabases
  • Unlike ExecuteAsync, ApplyEdits does not support Undo/Redo functionality
  • While ExecuteAsync requires a SaveEdits or DiscardEdits call to close the edit session, ApplyEdits implicitly closes both the edit session and edit operation.
  • ApplyEdits does not support updating the map.

It should be noted that ApplyEdits is intended for editing outside ArcGIS Pro. For all editing in an add-in, EditOperation should be used.

MCT exclusions

As explained previously, all methods in the ArcGIS.Core.Data API must be invoked on the Main CIM Thread (MCT). However, some exclusions exist. [ArcGIS.Core.Data.SpatialQueryFilter] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7495.html) and [ArcGIS.Core.Data.QueryFilter] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7365.html) can be constructed on any thread; however, [Search] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7524.html) and [Select] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7525.html) using the QueryFilter still have to be called on the MCT.

When in doubt, refer to the triple-slash document to determine whether the method can be invoked on any thread.

Known issues

When you obtain an [ArcGIS.Core.Data.Table] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7511.html) reference from [FeatureLayer] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic10630.html), for datastores other than file geodatabases and enterprise geodatabases and for methods other than [Search] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7524.html) and [Select] (http://pro.arcgis.com/en/pro-app/sdk/api-reference/#topic7525.html), there may be unexpected exceptions raised. In future releases, appropriate methods on the Table object for all the datastores will be supported.

The feature services API is not complete. Currently, the only operations supported are opening a feature service datastore, opening datasets in a feature service datastore, creating/deleting/updating attachments, and executing search and select on the feature classes and tables. GetSubtypes and Editing feature service tables and feature classes are not yet supported.

Developing with ArcGIS Pro

    Migration


Framework

    Add-ins

    Configurations

    Customization

    Styling


Arcade


Content


CoreHost


DataReviewer


Editing


Geodatabase

    3D Analyst Data

    Plugin Datasources

    Topology

    Linear Referencing

    Object Model Diagram


Geometry

    Relational Operations


Geoprocessing


Knowledge Graph


Layouts

    Reports


Map Authoring

    3D Analyst

    CIM

    Graphics

    Scene

    Stream

    Voxel


Map Exploration

    Map Tools


Networks

    Network Diagrams


Parcel Fabric


Raster


Sharing


Tasks


Workflow Manager Classic


Workflow Manager


Reference

Clone this wiki locally