Creating fields


Summary
This topic discusses the process of building a fields collection, adding a single field to an existing feature class, accessing and modifying a field's GeometryDef (before it's associated with a feature class), getting the minimum required fields for a feature class, and adding user-defined fields to the fields collection.


Building a field set

The following are the key interfaces required to build a new set of fields:
The following illustration shows the relationship between these interfaces and the Fields and Field classes:
The following code example uses IFieldsEdit to create a fields collection. IFieldEdit is used to modify the properties of a newly created field that is added to the fields collection. The resulting fields collection can be used to create a table in a geodatabase; however, a more convenient alternative (class description objects) is discussed later in this topic.
[C#]
public IFields CreateFieldsCollectionForTable()
{
    // Create a fields collection.
    IFields fields = new FieldsClass();

    // Cast to IFieldsEdit to modify the properties of the fields collection.
    IFieldsEdit fieldsEdit = (IFieldsEdit)fields;

    // Create the ObjectID field.
    IField oidField = new FieldClass();

    // Cast to IFieldEdit to modify the properties of the new field.
    IFieldEdit oidFieldEdit = (IFieldEdit)oidField;
    oidFieldEdit.Name_2 = "ObjectID";
    oidFieldEdit.AliasName_2 = "FID";
    oidFieldEdit.Type_2 = esriFieldType.esriFieldTypeOID;

    // Add the new field to the fields collection.
    fieldsEdit.AddField(oidField);

    // Create the text field.
    IField textField = new FieldClass();
    IFieldEdit textFieldEdit = (IFieldEdit)textField;
    textFieldEdit.Length_2 = 30; 
        // Only string fields require that you set the length.
    textFieldEdit.Name_2 = "Owner";
    textFieldEdit.Type_2 = esriFieldType.esriFieldTypeString;

    // Add the new field to the fields collection.
    fieldsEdit.AddField(textField);

    return fields;
}
[VB.NET]
Public Function CreateFieldsCollectionForTable() As IFields
    
    ' Create a fields collection.
    Dim fields As IFields = New FieldsClass()
    
    ' Cast to IFieldsEdit to modify the properties of the fields collection.
    Dim fieldsEdit As IFieldsEdit = CType(fields, IFieldsEdit)
    
    ' Create the ObjectID field.
    Dim oidField As IField = New FieldClass()
    
    ' Cast to IFieldEdit to modify the properties of the new field.
    Dim oidFieldEdit As IFieldEdit = CType(oidField, IFieldEdit)
    oidFieldEdit.Name_2 = "ObjectID"
    oidFieldEdit.AliasName_2 = "FID"
    oidFieldEdit.Type_2 = esriFieldType.esriFieldTypeOID
    
    ' Add the new field to the fields collection.
    fieldsEdit.AddField(oidField)
    
    ' Create the text field.
    Dim textField As IField = New FieldClass()
    Dim textFieldEdit As IFieldEdit = CType(textField, IFieldEdit)
    textFieldEdit.Length_2 = 30 ' Only string fields require that you set the length.
    textFieldEdit.Name_2 = "Owner"
    textFieldEdit.Type_2 = esriFieldType.esriFieldTypeString
    
    ' Add the new field to the fields collection.
    fieldsEdit.AddField(textField)
    
    Return fields
    
End Function

Adding a field to an existing dataset

The IClass.AddField method (inherited by ITable, IObjectClass, and IFeatureClass) can be used to add a single field to an existing table. The following code example shows how to add a field to a feature class. As with any schema editing, establish an exclusive lock on the class first (using the ISchemaLock interface). See the following code example:
[C#]
public void AddFieldToFeatureClass(IFeatureClass featureClass, IField field)
{
    ISchemaLock schemaLock = (ISchemaLock)featureClass;

    try
    {
        // A try block is necessary, as an exclusive lock might not be available.
        schemaLock.ChangeSchemaLock(esriSchemaLock.esriExclusiveSchemaLock);

        // Add the field.
        featureClass.AddField(field);
    }
    catch (Exception exc)
    {
        // Handle appropriately for your application.
        Console.WriteLine(exc.Message);
    }
    finally
    {
        // Set the lock to shared, whether or not an error occurred.
        schemaLock.ChangeSchemaLock(esriSchemaLock.esriSharedSchemaLock);
    }
}
[VB.NET]
Public Sub AddFieldToFeatureClass(ByVal featureClass As IFeatureClass, ByVal field As IField)
    
    Dim schemaLock As ISchemaLock = CType(featureClass, ISchemaLock)
    
    Try
    ' A try block is necessary, as an exclusive lock might not be available.
    schemaLock.ChangeSchemaLock(esriSchemaLock.esriExclusiveSchemaLock)
    
    ' Add the field.
    featureClass.AddField(field)
    Catch exc As Exception
    ' Handle appropriately for your application.
    Console.WriteLine(exc.Message)
    Finally
    ' Set the lock to shared, whether or not an error occurred.
    schemaLock.ChangeSchemaLock(esriSchemaLock.esriSharedSchemaLock)
    End Try
    
End Sub

Modifying the GeometryDef object

The GeometryDef object defines the spatial properties of a feature class. The most fundamental spatial property is the geometry type, for example, point, line, and polygon. Other necessary information to define the feature class includes the spatial referencing system—whether the vertices have height or measure data—and for geodatabases, the spatial index parameters.
A feature class's GeometryDef can be accessed from the class's Shape field (a field of type esriFieldTypeGeometry). The geometry type of the class is defined by a value from the esriGeometryType enumeration, but only the following values are acceptable with respect to GeometryDef objects:
  • esriGeometryPoint
  • esriGeometryPolyLine
  • esriGeometryPolygon
  • esriGeometryMultiPoint
  • esriGeometryMultiPatch
The IGeometryDef interface is used to inspect the properties of a GeometryDef instance. The following code example shows how to get an IGeometryDef reference from a feature class:
[C#]
public IGeometryDef GetGeometryDef(IFeatureClass featureClass)
{
    // First, determine the name of the shape field.
    String shapeFieldName = featureClass.ShapeFieldName;

    // Get the feature class fields collection and find the shape field index.
    IFields fields = featureClass.Fields;
    int geometryIndex = fields.FindField(shapeFieldName);

    // Use the index value to get the field.
    IField field = fields.get_Field(geometryIndex);

    // Get the GeometryDef from the field and return it.
    IGeometryDef geometryDef = field.GeometryDef;
    return geometryDef;
}
[VB.NET]
Public Function GetGeometryDef(ByVal featureClass As IFeatureClass) As IGeometryDef
    
    ' First, determine the name of the shape field.
    Dim shapeFieldName As String = featureClass.ShapeFieldName
    
    ' Get the feature class fields collection and find the shape field index.
    Dim fields As IFields = featureClass.Fields
    Dim geometryIndex As Integer = fields.FindField(shapeFieldName)
    
    ' Use the index value to get the field.
    Dim field As IField = fields.Field(geometryIndex)
    
    ' Get the GeometryDef from the field and return it.
    Dim geometryDef As IGeometryDef = field.GeometryDef
    
    Return geometryDef
    
End Function
The AvgNumPoints, GridCount, and GridSize properties are all attributes of the geodatabase spatial index. Personal geodatabase feature classes only support a single grid, while file and ArcSDE geodatabases support multiple grid levels. Shapefiles return zero for the grid count.
The IGeometryDefEdit interface is used when creating a GeometryDef object. It is typically used when defining a new feature class or feature dataset.
IGeometryDefEdit cannot be used to modify an existing GeometryDef object that is attached to a feature class. Use IGeoDatasetSchemaEdit to make these changes.

Getting the minimum required fields for a feature class

The IFeatureClassDescription and IObjectClassDescription interfaces can be used to obtain the minimum required fields for object classes (tables) and feature classes.
The following code example shows IGeometryDefEdit being used to edit the GeometryDef object on a shape field in a fields collection returned from the required fields for a feature class. The following code example shows how to get a set of required fields for a feature class, modify the GeometryDef, and add a field of type double:
[C#]
public IFields CreateFieldsCollectionForFeatureClass(ISpatialReference
    spatialReference)
{
    // Use the feature class description to return the required fields in a fields collection.
    IFeatureClassDescription fcDesc = new FeatureClassDescriptionClass();
    IObjectClassDescription ocDesc = (IObjectClassDescription)fcDesc;

    // Create the fields using the required fields method.
    IFields fields = ocDesc.RequiredFields;

    // Locate the shape field with the name from the feature class description.
    int shapeFieldIndex = fields.FindField(fcDesc.ShapeFieldName);
    IField shapeField = fields.get_Field(shapeFieldIndex);

    // Modify the GeometryDef object before using the fields collection to create a 
    // feature class.
    IGeometryDef geometryDef = shapeField.GeometryDef;
    IGeometryDefEdit geometryDefEdit = (IGeometryDefEdit)geometryDef;

    // Alter the feature class geometry type to lines (default is polygons).
    geometryDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPolyline;
    geometryDefEdit.HasM_2 = true;
    geometryDefEdit.GridCount_2 = 1;

    // Set the first grid size to zero and allow ArcGIS to determine a valid grid size.
    geometryDefEdit.set_GridSize(0, 0);
    geometryDefEdit.SpatialReference_2 = spatialReference;

    // Because the fields collection already exists, the AddField method on the IFieldsEdit 
    // interface will be used to add a field that is not required to the fields collection.
    IFieldsEdit fieldsEdit = (IFieldsEdit)fields;
    IField incomeField = new FieldClass();
    IFieldEdit incomeFieldEdit = (IFieldEdit)incomeField;

    // Create a user-defined double field.
    incomeFieldEdit.AliasName_2 = "Average income for 1999-2000";
    incomeFieldEdit.Editable_2 = true;
    incomeFieldEdit.IsNullable_2 = false;
    incomeFieldEdit.Name_2 = "average_income";
    incomeFieldEdit.Precision_2 = 2;
    incomeFieldEdit.Scale_2 = 5;
    incomeFieldEdit.Type_2 = esriFieldType.esriFieldTypeDouble;
    fieldsEdit.AddField(incomeField);

    return fields;
}
[VB.NET]
Public Function CreateFieldsCollectionForFeatureClass(ByVal spatialReference As ISpatialReference) As IFields
    
    ' Use the feature class description to return the required fields in a fields collection.
    Dim fcDesc As IFeatureClassDescription = New FeatureClassDescriptionClass()
    Dim ocDesc As IObjectClassDescription = CType(fcDesc, IObjectClassDescription)
    
    ' Create the fields using the required fields method.
    Dim fields As IFields = ocDesc.RequiredFields
    
    ' Locate the shape field with the name from the feature class description.
    Dim shapeFieldIndex As Integer = fields.FindField(fcDesc.ShapeFieldName)
    Dim shapeField As IField = fields.Field(shapeFieldIndex)
    
    ' Modify the GeometryDef object before using the fields collection to create a feature class.
    Dim geometryDef As IGeometryDef = shapeField.GeometryDef
    Dim geometryDefEdit As IGeometryDefEdit = CType(geometryDef, IGeometryDefEdit)
    
    ' Alter the feature class geometry type to lines (default is polygons).
    geometryDefEdit.GeometryType_2 = esriGeometryType.esriGeometryPolyline
    geometryDefEdit.HasM_2 = True
    geometryDefEdit.GridCount_2 = 1
    
    ' Set the first grid size to zero and allow ArcGIS to determine a valid grid size.
    geometryDefEdit.GridSize_2(0) = 0
    geometryDefEdit.SpatialReference_2 = spatialReference
    
    ' Because the fields collection already exists, the AddField method on the IFieldsEdit
    ' interface will be used to add a field that is not required to the fields collection.
    Dim fieldsEdit As IFieldsEdit = CType(fields, IFieldsEdit)
    Dim incomeField As IField = New FieldClass()
    Dim incomeFieldEdit As IFieldEdit = CType(incomeField, IFieldEdit)
    
    ' Create a user-defined double field.
    incomeFieldEdit.AliasName_2 = "Average income for 1999-2000"
    incomeFieldEdit.Editable_2 = True
    incomeFieldEdit.IsNullable_2 = False
    incomeFieldEdit.Name_2 = "average_income"
    incomeFieldEdit.Precision_2 = 2
    incomeFieldEdit.Scale_2 = 5
    incomeFieldEdit.Type_2 = esriFieldType.esriFieldTypeDouble
    fieldsEdit.AddField(incomeField)
    
    Return fields
    
End Function

Validating fields

Before creating a dataset with a set of fields, Fields objects (and the fields they contain) should be validated using the IFieldChecker.Validate method. This method returns an enumerator containing information about each error found in the fields, as well as a "fixed" fields collection. Problems with field names that can prevent the creation of a dataset include exceeding a maximum length, including an invalid character, attempting to use a reserved word as a field name, or including two or more fields with the same names. The first three of these problems are data source-specific, for example, shapefiles and geodatabase feature classes have different maximum field name lengths.
Developers working with SDE should be aware of certain field names that conflict with properties used internally by SDE for storing geometry, for example, "LEN." Although not strictly prohibited, using these field names result in qualification of the field name, and should be avoided. For more details and a complete list of field names that conflict with SDE properties, see IFields2.
The following code example shows how to validate a set of fields using the IFieldChecker interface:
[C#]
public IFields ValidateFieldsForWorkspace(IFields fields, IWorkspace workspace)
{
    // Create a field checker.
    IFieldChecker fieldChecker = new FieldCheckerClass();
    fieldChecker.ValidateWorkspace = workspace;

    // Validate the fields.
    IEnumFieldError enumFieldError = null;
    IFields validatedFields = null;
    fieldChecker.Validate(fields, out enumFieldError, out validatedFields);

    // Display the field errors.
    IFieldError fieldError = null;
    enumFieldError.Reset();
    while ((fieldError = enumFieldError.Next()) != null)
    {
        IField errorField = fields.get_Field(fieldError.FieldIndex);
        Console.WriteLine("Field '{0}': Error '{1}'", errorField.Name,
            fieldError.FieldError);
    }

    // Return the validated fields.
    return validatedFields;
}
[VB.NET]
Public Function ValidateFieldsForWorkspace(ByVal fields As IFields, ByVal workspace As IWorkspace) As IFields
    ' Create a field checker.
    Dim fieldChecker As IFieldChecker = New FieldCheckerClass()
    fieldChecker.ValidateWorkspace = workspace
    
    ' Validate the fields.
    Dim enumFieldError As IEnumFieldError = Nothing
    Dim validatedFields As IFields = Nothing
    fieldChecker.Validate(fields, enumFieldError, validatedFields)
    
    ' Display the field errors.
    enumFieldError.Reset()
    Dim fieldError As IFieldError = enumFieldError.Next()
    While Not fieldError Is Nothing
        Dim errorField As IField = fields.Field(fieldError.FieldIndex)
        Console.WriteLine("Field '{0}': Error '{1}'", errorField.Name, fieldError.FieldError)
        fieldError = enumFieldError.Next()
    End While
    
    ' Return the validated fields.
    Return validatedFields
End Function






To use the code in this topic, reference the following assemblies in your Visual Studio project. In the code files, you will need using (C#) or Imports (VB .NET) directives for the corresponding namespaces (given in parenthesis below if different from the assembly name):
Additional Requirements
  • If working in ArcSDE, a Standard or an Advanced license is required for ArcGIS for Desktop, and the Geodatabase Update extension is required for ArcGIS Engine.

Development licensing Deployment licensing
ArcGIS for Desktop Basic ArcGIS for Desktop Basic
ArcGIS for Desktop Standard ArcGIS for Desktop Standard
ArcGIS for Desktop Advanced ArcGIS for Desktop Advanced
Engine Developer Kit Engine: Geodatabase Update