In this topic
- About creating a relationship class in the geodatabase
- Relationship class parameters
- Relationship class name (relClassName)
- Cardinality (esriRelCardinality)
- Origin class and destination class (OriginClass and DestinationClass)
- Origin primary and foreign keys (OriginPrimaryKey and OriginForeignKey)
- Simple vs. a composite relationship (IsComposite)
- Relationship attributes (IsAttributed and relAttrFields)
- Destination primary and foreign keys (destPrimaryKey and destForeignKey)
- Relationship class labels (forwardLabel and backwardLabel)
- Notification (esriRelNotification)
- Creating a simple relationship class in a feature dataset using IRelationshipClassContainer
- Creating a composite stand-alone relationship class using IFeatureWorkspace
- Creating an attributed relationship class using IFeatureWorkspace
About creating a relationship class in the geodatabase
Geodatabase relationship classes are similar to relationships in a DBMS. Relationship classes are used to manage a relationship between two object classes (feature classes and tables) in a geodatabase. Both of the object classes must be stored in the same geodatabase as the relationship class.
Since the relationship classes are stored in the geodatabase, they are always available when working with either of the related object classes. Relationship classes offer many other benefits while editing and working with data. They can help facilitate editing while lowering maintenance costs by providing automatic updates to related objects. Also, since relationship classes are stored in the geodatabase, they can also be managed with versions, which allow multiple users to edit the features or records in a relationship at the same time.
Relationship classes can be created by calling the CreateRelationshipClass method on the IFeatureWorkspace interface or on the IRelationshipClassContainer interface. The main difference is that the IRelationshipClassContainer is used to create relationship classes inside a feature dataset and IFeatureWorkspace is used to create stand-alone relationship classes. If one or both of the object classes participating in the relationship class are stored in a feature dataset, the relationship class can also be stored in the feature dataset or as a stand-alone object in the geodatabase. However, if both of the object classes are stored as stand-alone object classes in the geodatabase, then the relationship class must also be created as a stand-alone object. There is no functional difference between storing a relationship class inside a feature dataset or as a stand-alone object. The option is primarily for organizational purposes.
Relationship class parameters
There are a many different parameters that should be considered before a relationship class can be created. The parameter requirements are the same when using the CreateRelationshipClass method on either of the interfaces. These parameters define how relationship classes are created as well as their functional behavior. See the following:
public IRelationshipClass CreateRelationshipClass (
string relClassName,
IObjectClass OriginClass,
IObjectClass DestinationClass,
string forwardLabel,
string backwardLabel,
esriRelCardinality Cardinality,
esriRelNotification Notification,
bool IsComposite,
bool IsAttributed,
IFields relAttrFields,
string OriginPrimaryKey,
string destPrimaryKey,
string OriginForeignKey,
string destForeignKey
);
Give careful consideration when specifying these parameters because once the relationship class is created, only three of the parameters can be modified using the IRelClassSchemaEdit interface. This interface allows the forward and backward labels as well as the relationship type (that is, simple or composite) to be modified after the class has been created. To change the other properties, such as cardinality, the relationship class must be deleted and recreated with the new parameters. For more information, see IRelClassSchemaEdit.
The following sections discuss the parameters required to create a relationship class. The order in which the parameters are discussed is based on their relative importance as well as how commonly they are utilized during the creation of a relationship class.
Relationship class name (relClassName)
This string parameter is used to set the name of the relationship class. The relationship class name uniquely identifies it within the geodatabase. The specified name cannot contain spaces, punctuation, or start with a number. Ensure that the name of the relationship class is unique. This can be done by using the IWorkspace2.NameExists property.
Cardinality (esriRelCardinality)
The cardinality parameter is used to specify the number of objects in the origin class that can relate to a number of objects in the destination class. A relationship can have one of the following three cardinalities:
One-to-one
One origin object can relate to only one destination object. For example, a parcel can have only one legal description. See the following illustration:
One-to-many
One origin object can relate to multiple destination objects. For example, a parcel might have many buildings. In a one-to-many relationship, the one side must be the origin class and the many side must be the destination class. See the following illustration:
Many-to-many
The intermediate table contains foreign keys (FK) that relate to the primary keys (PK) in the origin and destination objects classes. These foreign keys are used to map the associations between the related objects. Each row associates one origin object with one destination object. Other attributes can also be stored in the intermediate relationship class table that describes the relationship.
- For more information about intermediate tables, see Relationship attributes (IsAttributed and relAttrFields).
- For more information about primary and foreign keys, see Origin primary and foreign keys (OriginPrimaryKey and OriginForeignKey) and Destination primary and foreign keys (destPrimaryKey and destForeignKey).
Relationship cardinality constants
Constant |
Value |
Description |
esriRelCardinalityOneToOne |
1 |
one-to-one |
esriRelCardinalityOneToMany |
2 |
one-to-many |
esriRelCardinalityManyToMany |
3 |
many-to-many |
Origin class and destination class (OriginClass and DestinationClass)
The IObjectClass parameters are used to indicate which object classes are participating in the relationship class. In a relationship class, one class acts as the origin and another as the destination. It is important not to confuse the two because there is different behavior associated with the origin and destination classes.
When deciding which object class will act as the origin and which will act as the destination, the first thing to consider is the cardinality of the relationship that exists between the two object classes. The cardinality is used to specify the number of objects in the origin class that can relate to the number of objects in the destination class. As previously mentioned, relationship classes support the following three cardinality types - one-to-one, one-to-many, and many-to-many.
Once the cardinality of the relationship is identified, it is important that the object classes are assigned to their correct roles (origin or destination) in the relationship. In both simple and composite relationships, the destination objects are modified when the origin objects are deleted. In a simple relationship when an origin object is deleted, the foreign key value is set to null in the related destination objects and in a composite relationship, the related destination objects are deleted in a process called cascade deletes. As a result, if wrong roles are chosen for the object classes, errors can be introduced into the geodatabase while editing.
The following illustration shows the importance of selecting the correct origin and destination object classes:
Case 1 - Parcel to zone (incorrect)
Case 2 - Zone to parcel (correct)
Origin primary and foreign keys (OriginPrimaryKey and OriginForeignKey)
-
Key field in origin class - The key field in the origin class of a relationship is called the primary key. Unlike a true primary key, the values in the primary key field in a relationship are not required to be unique for every object.
-
Key field in destination class - The key field in the destination class is called the foreign key. It contains values that match those of the primary key field in the origin class. Again, the key field values do not need to be unique for each row.
The key fields might have different names but must be of the same data type and contain the same kind of information, such as parcel IDs. Fields of all data types except a binary large object (BLOB), date, and raster might be key fields. The following table consists of a list of all the data types that can be used as key fields:
Relationship field types that can be used in a relationship class | |
Origin key |
Destination key |
OID |
OID, long integer |
Short integer |
Short integer |
Long integer |
OID, long integer |
Float |
Float |
Double |
Double |
Text |
Text |
GUID |
GUID, GlobalID |
GlobalID |
GUID |
When deciding on a primary key field, one option is to use the row ID field, commonly referred to as the ObjectID field. The ObjectID field guarantees a unique ID for each record. It is maintained by ArcGIS and cannot be modified. The ObjectID value of a given object never changes as long as it remains in its original class.
The OriginPrimaryKey and OriginForeignKey parameters are strings that represent the name of the fields in the origin and destination objects classes that will be used to navigate between related objects. It is important to ensure that the fields names specified as the parameters match the field names in the objects classes; otherwise, an Invalid relationship class specification error is returned when trying to create the relationship class. See the following code example:
[C#] // Creating a relationship class without an intermediate table.
IRelationshipClass relClass=featureWorkspace.CreateRelationshipClass
(nameOfRelClass, originClass, destinationClass, "owns", "is owned by",
esriRelCardinality.esriRelCardinalityOneToMany,
esriRelNotification.esriRelNotificationNone, true, false, null, "PARCEL_ID", "",
"PARCEL_ID", "");
[VB.NET] ' Creating a relationship class without an intermediate table.
Dim relClass As IRelationshipClass=featureWorkspace.CreateRelationshipClass(nameOfRelClass, originClass, _
destinationClass, "owns", "is owned by", esriRelCardinality.esriRelCardinalityOneToMany, _
esriRelNotification.esriRelNotificationNone, True, False, Nothing, "PARCEL_ID", "", "PARCEL_ID", "")
Simple vs. a composite relationship (IsComposite)
The IsComposite parameter is used to indicate whether a simple or composite relationship class should be created. Simple and composite relationships refer to the way referential integrity is maintained while editing related objects.
Simple relationship
In a simple relationship, related objects can exist independently of each other. For example, in a railroad network, there might be railroad crossings that have one or more related signal lamps. However, a railroad crossing can exist without a signal lamp, and signal lamps can exist on the railroad network where there are no railroad crossings.
When deleting an origin object in a simple relationship, the key field value for the matching destination object is set to null. Deleting a destination object has no effect on the origin object. See the following illustration:
Composite relationship
In a composite relationship, the destination objects are dependent on the lifetime of the origin objects. Through a process called cascade deletes, when an origin object is deleted, all related destination objects are deleted. With Forward messaging enabled, a composite relationship can also help maintain features spatially. Moving or rotating an origin feature causes the related destination features to move or rotate with it. It is important to note that because of this dependency on the origin objects, an object class can only be the destination in one composite relationship at a time. See the following illustration:
The IsComposite parameter is Boolean; setting it to true indicates the relationship will be composite and setting it to false indicates that the relationship will be simple. After a relationship class has been created, the IsComposite parameter can be changed using the AlterIsComposite method on the IRelClassSchemaEdit interface.
Relationship attributes (IsAttributed and relAttrFields)
The IsAttributed and the relAttrFields parameters optionally allow attributes to be stored about each individual relationship between objects in the origin and destination object classes. Any relationship class, whether simple or composite and of any particular cardinality can have attributes. The attribute fields are stored in an intermediate table along with the foreign key fields.
When the intermediate table is created, only the fields are generated automatically. ArcGIS does not know which origin objects are associated with which destination objects, so the rows must be manually created. Once a relationship is added to the intermediate table, the relationship's attributes can be populated. See the following illustration:
In the preceding illustration, there is a relationship class between parcels and owners, where owners own parcels and parcels are owned by owners. An attribute of each relationship could be the percentage of ownership.
The IsAttributed parameter is used to specify whether or not the relationship class is attributed. This parameter is a Boolean parameter. To create an attributed relationship class, set the parameter to true; otherwise, set it to false.
The relAttribFields parameter is optional and is used to pass in the attribute fields for attributed relationship classes. If an attributed relationship class is not being created, pass in a null value.
It is important that both of the parameters are set correctly for the type of relationship to be created. If the IsAttributed parameter is set to false but an IFields reference is passed in for the relAttribFields, the relationship is not created and the Invalid relationship class specification error is returned. However, if the IsAttributed parameter is set to true but a null value is passed in for the relAttribFields, an intermediate table is still created but it will only consist of the foreign key fields. See the following table:
IsAttributed |
relAttrFields | |
Relationship class
without attributes |
False |
Null |
Relationship class
with attributes |
True |
Populated
IFields object |
See the following code example:
[C#]
// Creating a non-attributed relationship class.
IRelationshipClass relClass=featureWorkspace.CreateRelationshipClass
(nameOfRelClass, originClass, destinationClass, "owns", "is owned by",
esriRelCardinality.esriRelCardinalityOneToMany,
esriRelNotification.esriRelNotificationNone, true, false, null, "PROPERTY_ID",
"", "PROPERTY_ID", "");
// Creating an attributed relationship class.
IRelationshipClass attributedRelClass=featureWorkspace.CreateRelationshipClass
(nameOfRelClass, originClass, destinationClass, "owns", "is owned by",
esriRelCardinality.esriRelCardinalityOneToMany,
esriRelNotification.esriRelNotificationNone, true, true, fields, "PROPERTY_ID",
"", "PROPERTY_ID", "");
[VB.NET] ' Creating a non-attributed relationship class.
Dim relClass As IRelationshipClass=featureWorkspace.CreateRelationshipClass(nameOfRelClass, originClass, _
destinationClass, "owns", "is owned by", esriRelCardinality.esriRelCardinalityOneToMany, _
esriRelNotification.esriRelNotificationNone, True, False, Nothing, "PROPERTY_ID", "", "PROPERTY_ID", "")
' Creating an attributed relationship class.
Dim attributedRelClass As IRelationshipClass=featureWorkspace.CreateRelationshipClass(nameOfRelClass, _
originClass, destinationClass, "owns", "is owned by", esriRelCardinality.esriRelCardinalityOneToMany, _
esriRelNotification.esriRelNotificationNone, True, True, fields, "PROPERTY_ID", "", "PROPERTY_ID", "")
Destination primary and foreign keys (destPrimaryKey and destForeignKey)
When creating a many-to-many and attributed relationship class, an intermediate table is automatically created. The intermediate table is used to map the relationships between the origin and destination objects. To map the relationships between objects, key fields are used in the origin and destination object classes, as well as the intermediate table.
The OriginPrimaryKey and DestinationPrimaryKey are the primary key fields in the origin and destination object classes. The OriginForeignKey and the DestinationForeignKey are the names of the corresponding foreign keys that will be created in the intermediate table representing the relationship class. See the following illustration:
Primary key fields
When selecting the OriginPrimaryKey and the DestinationPrimaryKey fields, it is important to select fields that can be used to uniquely identify the objects so that the each row in the intermediate table relates one origin object with one destination object. In the preceding illustration, the ObjectID (OID) and the Owner name fields are used to uniquely identify the objects in the origin and destination object classes.
The OriginPrimaryKey and the destPrimaryKey parameters are strings that represent the name of the fields in the origin and destination objects classes that will be used to navigate between related objects. It is important to ensure that the field names specified as the parameters match the field names in the objects classes; otherwise, an error is raised when trying to create the relationship class.
Foreign key fields
When creating the relationship class, the foreign key fields (OriginForeignKey and destForeignKey) parameters are strings that represent the name of the fields that will be created in the intermediate table. These fields will be used to navigate between related objects so it is important that the names reflect the primary keys so they can be easily identified in the intermediate table.
In the preceding illustration, the OriginForeignKey field is named Parcel_ID to indicate that it is the key field that relates to the Parcel object class and the DestinationForeignKey is named Owner to easily relate it back to the Owner object class.
When the relationship class is created, the intermediate table is empty. ArcGIS does not know which origin objects are associated with which destination objects, so the relationships must be added manually. As relationships are added to the intermediate table, the OriginForeignKey and the DestinationForeignKey fields are automatically populated with the related values in the OriginPrimaryKey and the DestinationPrimaryKey fields. See the following code example:
[C#] // Creating a relationship class with an intermediate table.
IRelationshipClass relClass=featureWorkspace.CreateRelationshipClass
(nameOfRelClass, originClass, destinationClass, "owns", "is owned by",
esriRelCardinality.esriRelCardinalityOneToMany,
esriRelNotification.esriRelNotificationNone, false, true, fields, "OID", "OWNER",
"Parcel_ID", "OWNER");
[VB.NET] ' Creating a relationship class with an intermediate table.
Dim relClass As IRelationshipClass=featureWorkspace.CreateRelationshipClass(nameOfRelClass, originClass, _
destinationClass, "owns", "is owned by", esriRelCardinality.esriRelCardinalityOneToMany, _
esriRelNotification.esriRelNotificationNone, False, True, fields, "OID", "OWNER", "Parcel_ID", "OWNER")
Do not add the foreign key fields to the IFields collection. The key fields are automatically generated when the relationship class is created. A unique relationship identifier (RID) field is also automatically created in the intermediate table.
Relationship class labels (forwardLabel and backwardLabel)
When creating a relationship class, the forward and backward labels are set using the two string parameters forwardLabel and backwardLabel. Forward and backward labels show in the Attributes and Identify results dialog boxes in ArcMap and assist in navigation between related objects. The forward label is shown and used when navigating from an origin object to a destination object, and the backward label is shown and used when navigating in the reverse direction. See the following illustration:
For example, in a parcel geodatabase there is an origin class that is a parcel layer and a destination class that is an owners table. The forward label can be set to "is owned by" meaning this parcel is owned by this owner and the backward label can be set to "owns" meaning this owner owns these parcels.
Notification (esriRelNotification)
The notification parameter is used to set the messaging that will be used in the relationship class. Messaging is used to have origin and destination objects send messages to notify one another when they are changed or created, allowing related objects to update appropriately.
Some examples of actions that require changes in one object to trigger an update in its related objects include the following:
- When moving or rotating a feature, related features should move or rotate along with it.
- When updating a feature, an attribute in a related feature should be updated automatically.
- Updating an origin objects can require related destination objects to update.
- Updating destination objects can require related origin objects to update.
- When creating an object in one of the participating object classes and related objects should be created or updated automatically.
- When deleting an object in one of the participating object classes and related objects should be updated or deleted automatically.
See the following illustration:
Although the messaging is set as a parameter when the relationship class is created, additional behavior must be programmed into the participating object classes to listen for the messages, then respond with the applicable behavior.
The only exception is when messaging is set to forward on a composite relationship class. When creating a composite relationship with forward messaging, moving or rotating an origin object causes related destination features to automatically move, rotate, or delete with it. Provided the relationship is set up correctly, this functionality works as soon as the relationship is created - no programming is required.
The following are the four types of messaging:
- None
- Forward
- Backward
- Both
Unless creating a composite relationship with forward messaging or intending to program custom behavior, set the message notification to none. Otherwise, messages needlessly generate each time an edit operation is performed, which slows performance. The messaging notification is set using the ESRI relationship notification constants. See the following table:
Constant |
Value |
Description |
Effect on simple relationships |
Effect on composite relationships |
esriRelNotificationNone |
1 |
None: No messages are sent |
Prevents messages from being sent, slightly improving performance |
|
esriRelNotificationForward |
2 |
Forward: Messages are sent only from origin objects to destination objects |
No effect unless customized with programming |
|
esriRelNotificationBackward |
3 |
Backward: Messages are sent only from destination objects to source objects |
No effect unless customized with programming |
|
esriRelNotificationBoth |
4 |
Both: Messages are sent in both directions |
No effect unless customized with programming |
|
Creating a simple relationship class in a feature dataset using IRelationshipClassContainer
The following code example shows how to create a simple relationship class in a feature dataset:
[C#] public IRelationshipClass CreateRelClassInFeatureDataset(IFeatureDataset
featureDataset, String nameOfRelClass, IObjectClass originClass, IObjectClass
destinationClass)
{
// Cast the feature dataset to the IRelationshipClassContainer interface.
IRelationshipClassContainer relClassContainer=(IRelationshipClassContainer)
featureDataset;
// Create the relationship class.
IRelationshipClass relClass=relClassContainer.CreateRelationshipClass
(nameOfRelClass, originClass, destinationClass, "owns", "is owned by",
esriRelCardinality.esriRelCardinalityOneToMany,
esriRelNotification.esriRelNotificationNone, false, false, null,
"PROPERTY_ID", "", "PROPERTY_ID", "");
return relClass;
}
[VB.NET] Public Function CreateRelClassInFeatureDataset(ByVal featureDataset As IFeatureDataset, ByVal nameOfRelClass As String, _
ByVal originClass As IObjectClass, ByVal destinationClass As IObjectClass) As IRelationshipClass
' Cast the feature dataset to the IRelationshipClassContainer interface.
Dim relClassContainer As IRelationshipClassContainer=CType(featureDataset, IRelationshipClassContainer)
' Create the relationship class.
Dim relClass As IRelationshipClass=relClassContainer.CreateRelationshipClass(nameOfRelClass, originClass, _
destinationClass, "owns", "is owned by", esriRelCardinality.esriRelCardinalityOneToMany, _
esriRelNotification.esriRelNotificationNone, False, False, Nothing, "PROPERTY_ID", "", "PROPERTY_ID", "")
Return relClass
End Function
Creating a composite stand-alone relationship class using IFeatureWorkspace
The following code example shows how to create a composite stand-alone relationship class:
[C#] public IRelationshipClass CreateCompositeRelClass(IFeatureWorkspace featureWorkspace,
String nameOfRelClass, IObjectClass originClass, IObjectClass destinationClass)
{
// Create the relationship class.
IRelationshipClass relClass=featureWorkspace.CreateRelationshipClass
(nameOfRelClass, originClass, destinationClass, "owns", "is owned by",
esriRelCardinality.esriRelCardinalityOneToMany,
esriRelNotification.esriRelNotificationNone, true, false, null,
"PROPERTY_ID", "", "PROPERTY_ID", "");
return relClass;
}
[VB.NET] Public Function CreateCompositeRelClass(ByVal featureWorkspace As IFeatureWorkspace, ByVal nameOfRelClass As String, _
ByVal originClass As IObjectClass, ByVal destinationClass As IObjectClass) As IRelationshipClass
' Create the relationship class.
Dim relClass As IRelationshipClass=featureWorkspace.CreateRelationshipClass(nameOfRelClass, originClass, _
destinationClass, "owns", "is owned by", esriRelCardinality.esriRelCardinalityOneToMany, _
esriRelNotification.esriRelNotificationNone, True, False, Nothing, "PROPERTY_ID", "", "PROPERTY_ID", "")
Return relClass
End Function
Creating an attributed relationship class using IFeatureWorkspace
The following code example shows how to create an attributed relationship class:
[C#] public IRelationshipClass CreateAttributedRelClass(IFeatureWorkspace
featureWorkspace)
{
// Open the participating classes from the workspace.
IObjectClass originClass=featureWorkspace.OpenFeatureClass("Parcels");
IObjectClass destinationClass=(IObjectClass)featureWorkspace.OpenTable(
"Owners");
// Create a fields collection for the relationship class.
IFields fields=new FieldsClass();
IFieldsEdit fieldsEdit=(IFieldsEdit)fields;
// Create a "percent owned" field and add it to the collection.
IField field=new FieldClass();
IFieldEdit fieldEdit=(IFieldEdit)field;
fieldEdit.Name_2="PercentOwned";
fieldEdit.Type_2=esriFieldType.esriFieldTypeInteger;
fieldsEdit.AddField(fieldEdit);
// Create the attributed relationship class.
IRelationshipClass relClass=featureWorkspace.CreateRelationshipClass(
"ParcelsToOwners", originClass, destinationClass, "owns", "is owned by",
esriRelCardinality.esriRelCardinalityOneToMany,
esriRelNotification.esriRelNotificationNone, false, true, fields,
"PROPERTY_ID", "OWNER_ID", "PROPERTY_ID", "OWNER_ID");
return relClass;
}
[VB.NET] Public Function CreateAttributedRelClass(ByVal featureWorkspace As IFeatureWorkspace) As IRelationshipClass
' Open the participating classes from the workspace.
Dim originClass As IObjectClass=featureWorkspace.OpenFeatureClass("Parcels")
Dim destinationClass As IObjectClass=CType(featureWorkspace.OpenTable("Owners"), IObjectClass)
' Create a fields collection for the relationship class.
Dim fields As IFields=New FieldsClass()
Dim fieldsEdit As IFieldsEdit=CType(fields, IFieldsEdit)
' Create a "percent owned" field and add it to the collection.
Dim field As IField=New FieldClass()
Dim fieldEdit As IFieldEdit=CType(field, IFieldEdit)
fieldEdit.Name_2="PercentOwned"
fieldEdit.Type_2=esriFieldType.esriFieldTypeInteger
fieldsEdit.AddField(fieldEdit)
' Create the attributed relationship class.
Dim relClass As IRelationshipClass=featureWorkspace.CreateRelationshipClass("ParcelsToOwners", originClass, _
destinationClass, "owns", "is owned by", esriRelCardinality.esriRelCardinalityOneToMany, _
esriRelNotification.esriRelNotificationNone, False, True, fields, "PROPERTY_ID", "OWNER_ID", _
"PROPERTY_ID", "OWNER_ID")
Return relClass
End Function
It is important to note that the order of the key fields changes when creating an attributed and/or a many-to-many relationship. In this case the order is OriginPrimaryKey, destPrimaryKey, OriginForeignKey, destForeignKey. The OriginPrimaryKey and the destPrimaryKey fields represent the fields present in the origin and destination object classes. The OriginForeignKey and the destForeignKey fields represent the fields that will be created in the intermediate table.
See Also:
Creating fieldsCreating feature classes
Creating tables
Creating feature datasets
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):
- ESRI.ArcGIS.Geodatabase
- ESRI.ArcGIS.Geometry
- ESRI.ArcGIS.System (ESRI.ArcGIS.esriSystem)
Development licensing | Deployment licensing |
---|---|
ArcGIS Desktop Standard | ArcGIS Desktop Standard |
ArcGIS Desktop Advanced | ArcGIS Desktop Advanced |
Engine Developer Kit | Engine: Geodatabase Update |