ArcGIS Pro SDK

Get started with the Data Definition Language (DDL) API in the ArcGIS Pro SDK for .NET

Overview

The release of ArcGIS Pro SDK 3.1 brings improvements to the Data Definition Language (DDL) API for geodatabases schema management. This API allows developers to create, modify, and delete geodatabases and their schema programmatically from scratch. Developers who rely on traditional geoprocessing tools for managing workspaces, datasets, fields, domains, subtypes, and relationship classes can use the DDL API to automate and extend the functionality of ArcGIS Pro.

The following functionalities are available on the specified geodatabase types:

Capability File Geodatabase Mobile Geodatabase Enterprise Geodatabase Memory Geodatabase
Tables (create, modify, rename, delete)
Feature classes (create, modify, rename, delete)
Feature datasets (create, change contents, rename, delete)
Domains (create, modify, rename, delete)
Annotation feature classes (create, modify, rename, delete)
Subtypes (create, modify, delete)
Relationship classes (create, modify, rename, delete)
Indexes (create, delete)
Geodatabases (create, delete)

Usage pattern

The DDL routines follow a common pattern. First, a Description class is used to specify the schema object to be created or deleted. The Description objects are either created by assigning desired values to a set of properties and parameters, or using existing schema objects, including tokens or existing definitions.

In this example, you will create a description of a table with fields. A TableDescription object describes a table. One property of a table description is a list of FieldDescription objects to specify the fields.

// Create a FieldDescription for the InspectionDate field
FieldDescription inspectionDateFieldDescription = new FieldDescription("InspectionDate", FieldType.Date)
{
    AliasName = "Inspection Date"
};
TableDescription inspectionTableDescription = new TableDescription(
    "Inspections", 
    new List<FieldDescription> { inspectionDateFieldDescription }
);

To obtain the TableDescription of a table that exists in the geodatabase, pass the Definition object to the constructor.

TableDescription inspectionTableDescription = new TableDescription(inspectionTableDefinition);

The schema objects are created, modified, and deleted using a SchemaBuilder object, which is constructed from the Geodatabase object where the schema operations will take place.

// Create a SchemaBuilder Object
SchemaBuilder schemaBuilder = new SchemaBuilder(geodatabase);

DDL operations for creation are enqueued with the schema builder using the Create method.

// Add the creation of the table to our list of DDL tasks
TableToken tableToken = schemaBuilder.Create(tableDescription);

The set of DDL operations is then run with a call to Build. If the process fails, the ErrorMessages property of the SchemaBuilder object can be queried to find out what went wrong.

// Run the DDL
bool success = schemaBuilder.Build();
IReadOnlyList<string> errorMessages = schemaBuilder.ErrorMessages;

When using the Modify method to modify schema, there are two common patterns to obtain a modified description to pass to the method:

  1. Copy properties and attributes from the current description to a new description object, except for the properties that need to be modified. This is often done if the property to modify is read-only in the description class.
  2. Directly modify the current description object if the property is not read-only.

Tokens

Each call to the Create method returns a Token object. These tokens are used to specify the dependencies between DDL operations. For example, the Create(FeatureDatasetDescription) routine returns a FeatureDatasetToken. Developers can use this token to create feature classes inside a feature dataset.

schemaBuilder.Create(FeatureDatasetDescription(FeatureDatasetToken), FeatureClassDescription)

The FeatureDatasetToken is used to create a FeatureDatasetDescription.

Tokens can also be used to create a Description representing the dataset from the enqueued operation:

TableDescription anotherTableDescription = new TableDescription(tableToken)

Next, let’s look at some of the key workflows using the DDL API. The following code snippets show various patterns for some common operations—other patterns are also possible.

Workspaces

The DDL API supports creation and deletion of the memory and local workspaces. You can create and delete memory, file, and mobile geodatabases using static methods from the SchemaBuilder class using the CreateGeodatabase and DeleteGeodatabase methods.

// Creates a file geodatabase at specified path
SchemaBuilder.CreateGeodatabase(new FileGeodatabaseConnectionPath(pathUri));
// Creates a mobile geodatabase at specified path
SchemaBuilder.CreateGeodatabase(new MobileGeodatabaseConnectionPath(pathUri));
// Creates the default memory geodatabase
SchemaBuilder.CreateGeodatabase(new MemoryConnectionProperties());

// Deletes a file geodatabase at specified path
SchemaBuilder.DeleteGeodatabase(new FileGeodatabaseConnectionPath(pathUri));
// Deletes a mobile geodatabase at specified path
SchemaBuilder.DeleteGeodatabase(new MobileGeodatabaseConnectionPath(pathUri));
// Deletes the default memory geodatabase
SchemaBuilder.DeleteGeodatabase(new MemoryConnectionProperties());

Fields

The FieldDescription class in the DDL API allows developer to specify the schema of attribute fields, with support for a range of field types, including ObjectID and GlobalID fields, as well as features including domains and default values.

// Creating a domain field named as 'PipeMaterials' for materials used in pipes
FieldDescription pipeMaterialDomainField = FieldDescription.CreateDomainField(
    "PipeMaterials", 
    new CodedValueDomainDescription(
        "MaterialType", 
        FieldType.String, 
        new SortedList<object, string>(){{"Cu","Copper"}, {"Fe","Iron"}}
    )
);


// Creating a double field named as 'PipeLength' with default value of 1.5
FieldDescription pipeLength = new FieldDescription("PipeLength", FieldType.Double);
pipeLength.SetDefaultValue(1.5);

To create a domain using the DDL API, see the Domains section.

Table, feature class, and feature dataset

The TableDescription, FeatureClassDescription, and AnnotationFeatureClassDescription classes are used to create a standalone table, feature class, or an annotation feature class respectively with the DDL API.

Certain parameters are required in each constructor when creating these descriptions without a prior schema object such as a Token or Description. The TableDescription class requires the table’s name and a set of attribute fields to create a standalone table. Similarly, constructing the FeatureClassDescription object requires the feature class’s name, a set of attribute fields, and the shape information of a feature class. In addition to the information required for a feature class, constructing the AnnotationFeatureClassDescription object requires the labels and their placement information.

These datasets can also be created inside a feature dataset if feature dataset information is provided.

Create a table and feature class

In this example, you will create a feature class. First, create a ShapeDescription object to specify the geometry type and spatial reference. A FieldDescription object is specified in the constructor, contained in the pipeLength variable. Other fields required for this feature class are generated by default when building the schema.

// Create feature class called Pipe
ShapeDescription shapeDescription = new ShapeDescription(GeometryType.Polyline, SpatialReferenceBuilder.CreateSpatialReference(4326));
FeatureClassDescription featureClassDescription = new FeatureClassDescription(
    "Pipe", 
    new List<FieldDescription> { pipeLength }, 
    shapeDescription
);

schemaBuilder.Create(featureClassDescription);
bool success = schemaBuilder.Build();
ArcGIS Pro screenshot of a Fields view of a Pipe feature class. Four fields are visible: PipeLength, OBJECTID, Shape, and Shape_Length.
The resulting Fields view of the new feature class.

Modify the table and feature class

To obtain the schema of the existing feature class, first get a FeatureClassDefinition object (called featureClassDefinition) from the datastore. Then add a field to the Description by first creating a new Description, as the list of fields is a read-only property, and call Modify() on the description.

// Use definition to make a description object, and a field to the original feature class
FieldDescription pipeDiameter = new FieldDescription("PipeDiameter", FieldType.Double);
FeatureClassDescription originalDescription = new FeatureClassDescription(featureClassDefinition);
FeatureClassDescription modifiedDescription = new FeatureClassDescription(
    originalDescription.Name, 
    originalDescription.FieldDescriptions.Append(pipeDiameter), 
    originalDescription.ShapeDescription
);

schemaBuilder.Modify(modifiedDescription);
bool success = schemaBuilder.Build();
ArcGIS Pro screenshot of a Fields view of the Pipe feature class. Five fields are visible: PipeLength, OBJECTID, Shape, Shape_Length, and PipeDiameter. The added field, PipeDiameter, is emphasized.
The resulting Fields view of the modified feature class.

Delete a table and feature class

Similar to the pattern for modifying feature classes, obtain Definitions for the feature class using the datastore, and then create a description. Then call Delete() on the descriptions.

// Use definition to make description object and delete it
FeatureClassDescription featureClassDescription = new FeatureClassDescription(featureClassDefinition);
schemaBuilder.Delete(featureClassDescription);

bool success = schemaBuilder.Build();

Domains

Attribute domains are rules that describes the acceptable values of a field for a given field type. They ensure data integrity by limiting the choice of values for a particular field.

The DDL API supports creation of both types of domains–Range and Coded Value. Range Domains specify a valid range of values for numeric and date attribute fields, and Coded Value Domain specify a valid set of values for any type of attribute field. Domains can also be modified or deleted using the DDL API. After creating a domain, they can be associated with fields via their FieldDescription object.

Create domains

To create domains, first create a Range Domain description as well as a Coded Value Domain description using their respective constructors. The range domain will have a minimum value of 1.1 and a maximum value of 9.5. The coded value domain will have 2 coded values representing pipe materials.

// Create a range domain description
RangeDomainDescription rangeDomainDescription = new RangeDomainDescription("PipeLengthRangeDomain", FieldType.Double, 1.1, 9.5)
{
    Description = "A new range domain",
};

// Create a coded value domain description
CodedValueDomainDescription codedValueDomainDescription = new CodedValueDomainDescription(
    "MaterialType",
    FieldType.String,
    new SortedList<object, string>() { { "Cu", "Copper" }, { "Fe", "Iron" } }
);

schemaBuilder.Create(rangeDomainDescription);
schemaBuilder.Create(codedValueDomainDescription);

bool success = schemaBuilder.Build();
ArcGIS Pro screenshot of the Domains view of a geodatabase. Two domains are visible: MaterialType and PipeLengthRangeDomain.
The resulting Domains view of the geodatabase.

Modify domains

Because you are modifying properties of the domains that cannot be set, you will create a modified domain description and copy some properties over from the original. The original domain was created using a constructor, which takes the Domain object itself as a parameter. The Domain object can be obtained from the geodatabase. Note that the description of the Range Domain is not copied, and thus does not appear in the modified domain.

// Modify range of the range domain
RangeDomainDescription originalRangeDomainDescription = new RangeDomainDescription(rangeDomain);
RangeDomainDescription modifiedRangeDomainDescription = new RangeDomainDescription(
    originalRangeDomainDescription.Name, 
    originalRangeDomainDescription.FieldType, 
    0.0, 10.0
);

// Modify coded values of the coded value domain
CodedValueDomainDescription originalCodedValueDomainDescription = new CodedValueDomainDescription(codedValueDomain);
SortedList<object, string> newCodedValuePairs = new SortedList<object, string>()
{
    { "Cu", "Copper" }, { "Fe", "Iron" }, { "Pvc", "Polyvinyl Chloride" }
};
CodedValueDomainDescription modifiedCodedValueDomainDescription = new CodedValueDomainDescription(
    originalCodedValueDomainDescription.Name, 
    originalCodedValueDomainDescription.FieldType,
    newCodedValuePairs
);

schemaBuilder.Modify(modifiedRangeDomainDescription);
schemaBuilder.Modify(modifiedCodedValueDomainDescription);
bool success = schemaBuilder.Build();
Diagram with two sets of screenshots showing the configuration of a domain before and after modification. The MaterialType domain has gained a coded value, while the range values for PipeLengthRange domain have changed from 1.1–9.5 to 0–10.
The resulting details for each domain before and after modification.

Delete Domains

Similar to the pattern for modifying domains, obtain Domain objects for both the Range and Coded Value domain using the datastore and then create descriptions using them. Then call Delete() on the descriptions.

RangeDomainDescription rangeDomainDescription = new RangeDomainDescription(rangeDomain);
CodedValueDomainDescription codedValueDomainDescription = new CodedValueDomainDescription(codedValueDomain);

schemaBuilder.Delete(rangeDomainDescription);
schemaBuilder.Delete(codedValueDomainDescription);
bool success = schemaBuilder.Build();

Subtypes

Subtypes are used to categorize objects in a single dataset that shares the same attributes. To add subtypes, you must have a subtype field in the dataset. The subtype field must be of long or short integer data type.

The DDL API provides patterns to assign an existing field as the subtype field and add subtype values in the dataset using the SubtypeFieldDescription class. The API also allows for modifications of the subtype list and unassigning a field as the subtype field. The class constructor takes a field name and code-name (key-value) pair of subtypes as parameters.

Designate a field as the subtype field

Suppose a field called PipeType is added to the previously created Pipe feature class. Obtain the FeatureClassDefinition object representing the table in order to modify it, and pass it into the FeatureClassDescription constructor. To set PipeType as the subtype field, create a SubtypeFieldDescription object with the field name as the first parameter of the constructor, and then call Modify().

// Assign the PipeType field as the subtype field
FeatureClassDescription featureClassDescription = new FeatureClassDescription(featureClassDefinition);
featureClassDescription.SubtypeFieldDescription = new SubtypeFieldDescription(
    "PipeType", 
    new Dictionary<int, string>
    {
        { 0, "water" },
        { 1, "sewage" }
    }
);

schemaBuilder.Modify(featureClassDescription);
bool success = schemaBuilder.Build();
ArcGIS Pro screenshot of a Fields view of the Pipe feature class. The PipeType field is emphasized, as it is the subtype field.
The resulting Fields view of the feature class is shown. Because PipeType is now the subtype field, it is bold.

Modify subtypes

To modify the subtype, you will rely on the pattern of accessing the SubtypeFieldDescription from the properties of the feature class’ FeatureClassDescription. Then call Modify().

// Remove a subtype from the PipeType subtype field
FeatureClassDescription featureClassDescription = new FeatureClassDescription(featureClassDefinition);
featureClassDescription.SubtypeFieldDescription.Subtypes.Remove(1);

schemaBuilder.Modify(featureClassDescription);
bool success = schemaBuilder.Build();
Diagram with two ArcGIS Pro screenshots, each of the subtypes view of the Pipe feature class. Before, there are two possible values for the subtype field and only one after.
The resulting details for each domain before and after modification.

Remove subtype designation

To modify the subtype, you will rely on the pattern of accessing the SubtypeFieldDescription from the properties of the feature class’ FeatureClassDescription. To remove the subtype, set the property to null, and then call Modify().

// Unassign the PipeType field as the subtype field
FeatureClassDescription featureClassDescription = new FeatureClassDescription(featureClassDefinition);
featureClassDescription.SubtypeFieldDescription = null;

schemaBuilder.Modify(featureClassDescription);
bool success = schemaBuilder.Build();

Relationship Class

Relationship classes define the associations between objects in one feature class or table to objects in another feature class or table. ArcGIS Pro supports one-to-one, one-to-many, and many-to-many and may have attributes about the relationship itself.

For the DDL API, the RelationshipClassDescription class describes the relationship class between two classes as well as the origin and foreign key fields participating in the relationship.

Attributed relationship classes can contain their own attributes for each relationship between objects in the origin and destination class and are described by the AttributedRelationshipDescription class.

Create a relationship class

To create a relationship class from scratch without prior schema, description objects for both the origin table (pipeFeatureClassDescription) and destination table (inspectionDateTableDescription) are required for the constructor. You will also pass the name of the origin primary key field and origin foreign key field, which have been already created.

// Create relationship from pipes to inspection dates
FeatureClassDescription pipeFeatureClassDescription = new FeatureClassDescription(pipeFeatureClassDefinition);
TableDescription inspectionDateTableDescription = new TableDescription(inspectionDateTableDefinition);

RelationshipClassDescription relationshipClassDescription = new RelationshipClassDescription(
    "PipeToInspectionDate",
    pipeFeatureClassDescription, inspectionDateTableDescription, 
    RelationshipCardinality.OneToMany, 
    "PipeID", "InspectionID"
);

schemaBuilder.Create(relationshipClassDescription);
bool success = schemaBuilder.Build();
ArcGIS Pro screenshot showing the the properties of the PipeToInspectionDate relationship class. The properties match chosen parameters in the code.
The properties of the resulting relationship class are shown.

Modify relationship class

To obtain the schema of the existing relationship class, you will first get a RelationshipClassDefinition object from the datastore. Then change the split policy property on a created RelationshipClassDescription object and call Modify() on the description.

// Modify relationship split policy
RelationshipClassDescription relationshipClassDescription = new RelationshipClassDescription(relationshipClassDefinition);
relationshipClassDescription.RelationshipSplitPolicy = RelationshipSplitPolicy.UseDefault;

schemaBuilder.Modify(relationshipClassDescription);
bool success = schemaBuilder.Build();

Delete a relationship class

Similar to the pattern for modifying relationship classes, obtain the RelationshipClassDefinition object using the datastore, and then create a Description object using it. Then call Delete() on the description.

// Delete the relationship class
RelationshipClassDescription relationshipClassDescription = new RelationshipClassDescription(relationshipClassDefinition);

schemaBuilder.Delete(relationshipClassDescription);
bool success = schemaBuilder.Build();

Takeaway

The DDL API supports developers, users, and business partners who want to create and manipulate their datasets using the ArcGIS Pro SDK. Examples of workflows include storing results of operations in new datasets, creating temporary memory datastores for nonpersistent data, or programmatically modifying geodatabase schema based on user needs.

While geoprocessing tools and Python remain the preferred way to perform and automate large-scale schema operations, support for manipulating geodatabase schema directly in the ArcGIS Pro SDK provides you with another powerful way to extend the functionality of ArcGIS Pro. Please refer to the DDL Conceptual Document and the geodatabase Object Model Diagram for additional details.

 

About the authors

Aashis Lamsal is a Product Engineer at Esri, primarily working in the ArcGIS Pro and ArcGIS Enterprise SDKs. He has 10+ years of GIS application development experience and a background in epidemiology, natural resources, utilities, and more.

Jacob is a Student Technician in the Software Products division at Esri. He is also currently studying computer science as an undergraduate student at UCLA.

Subscribe
Notify of
0 Comments
Inline Feedbacks
View all comments

Next Article

Harnessing the Power of Imagery: A Programmatic Approach

Read this article