Getting a list of schema differences between replicas


Summary
The process of replica creation involves defining the datasets to replicate. Once a replica is created, changes can be independently made to the schemas of the datasets in each replicated geodatabase. Tools are provided to compare the replicas and return the list of the schema differences. Additional tools can be used to apply the schema changes from one replica geodatabase to the other.
The classes from the schema change export and import the object model in the geodatabase distributed library allow the schema differences to be acquired programmatically. This topic describes how to use the object model to get the list of schema differences.


About getting a list of schema differences between replicas

To get the schema differences, first initialize the SchemaChanges class using the ISchemaChangesInit interface.
The interface provides three Init methods. All three require the target workspace to be specified. The target references the replica being compared to. Each method differs in how it allows the source to be referenced. The source is the replica to compare from.
If both replica geodatabases are on the same network, the source can be specified using the replica directly from the source geodatabase. If the geodatabases are on different networks, a replica schema file that describes the replica in the source geodatabase can be generated, sent, and used for the comparison. See the ReplicaSchemaExporter coclass and IExportSchema interface for how to generate the replica schema file.
The third way to specify the source is by using a replica schema differences file. This file already contains the schema differences between the replicas. See the ReplicaSchemaExporter co-class and IExportSchema interface for how to generate the replica schema differences file.
The following code example shows two methods to initialize the SchemaChange class. One method is for the case where the source replica is being compared against directly, and one is for either of the files previously described.
[C#]
// This function takes the two SDE workspaces and replica, and gets the schema changes. 
public void ListSchemaChanges(IWorkspace targetWorkspace, IWorkspace sourceWorkspace,
    String replicaName)
{
    // Get the replica from the source and the workspace name object for the target.
    IWorkspaceReplicas workspaceReplicas = (IWorkspaceReplicas)sourceWorkspace;
    IReplica replica = workspaceReplicas.get_ReplicaByName(replicaName);
    IDataset dataset = (IDataset)targetWorkspace;
    IWorkspaceName workspaceName = (IWorkspaceName)dataset.FullName;

    // Initialize the schema changes object.
    ISchemaChanges schemaChanges = new SchemaChangesClass();
    ISchemaChangesInit schemaChangesInit = (ISchemaChangesInit)schemaChanges;
    schemaChangesInit.Init(replica, workspaceName);

    // Print the changes.
    PrintSchemaChanges(schemaChanges.GetChanges(), "");
}

// This function takes the target workspaces and either the schema file 
// for the relative replica or a schema changes file, and gets the schema changes.
// Set the isSchemaChangeFile to true if it is a schema changes file.
public void ListSchemaChanges(IWorkspace targetWorkspace, String schemaFile, Boolean
    isSchemaChangeFile)
{
    // Workspace name object for the target.
    IDataset dataset = (IDataset)targetWorkspace;
    IWorkspaceName workspaceName = (IWorkspaceName)dataset.FullName;

    // Initialize the schema changes object.
    ISchemaChangesInit schemaChangesInit = (ISchemaChangesInit)new SchemaChanges();
    if (isSchemaChangeFile)
    {
        schemaChangesInit.InitFromSchemaDifferencesDocument(schemaFile,
            workspaceName);
    }
    else
    {
        schemaChangesInit.InitFromSchemaDocument(schemaFile, workspaceName);
    }
    ISchemaChanges schemaChanges = (ISchemaChanges)schemaChangesInit;

    // Print the changes.
    PrintSchemaChanges(schemaChanges.GetChanges(), "");
}
[VB.NET]

' This function takes the two SDE workspaces and replica, and gets the schema changes.

Public Sub ListSchemaChanges(ByVal targetWorkspace As IWorkspace, ByVal sourceWorkspace As IWorkspace, ByVal replicaName As String)
    
    ' Get the replica from the source and the workspace name object for the target.
    Dim workspaceReplicas As IWorkspaceReplicas = CType(sourceWorkspace, IWorkspaceReplicas)
    Dim replica As IReplica = workspaceReplicas.ReplicaByName(replicaName)
    Dim dataset As IDataset = CType(targetWorkspace, IDataset)
    Dim Name As IName = dataset.FullName
    Dim workspaceName As IWorkspaceName = CType(Name, IWorkspaceName)
    
    ' Initialize the schema changes object.
    Dim schemaChanges As ISchemaChanges = New SchemaChangesClass()
    Dim schemaChangesInit As ISchemaChangesInit = CType(schemaChanges, ISchemaChangesInit)
    schemaChangesInit.Init(replica, workspaceName)
    
    ' Print the changes.
    PrintSchemaChanges(schemaChanges.GetChanges(), "")
    
End Sub

' This function takes the target workspaces and either the schema file
' for the relative replica or a schema changes file, and gets the schema changes.
' Set the isSchemaChangeFile to true if it is a schema changes file.

Public Sub ListSchemaChanges(ByVal targetWorkspace As IWorkspace, ByVal schemaFile As String, ByVal isSchemaChangeFile As Boolean)
    
    ' Workspace name object for the target.
    Dim dataset As IDataset = CType(targetWorkspace, IDataset)
    Dim Name As IName = dataset.FullName
    Dim workspaceName As IWorkspaceName = CType(Name, IWorkspaceName)
    
    ' Initialize the schema changes object.
    Dim schemaChangesInit As ISchemaChangesInit = New SchemaChangesClass()
    If isSchemaChangeFile Then
        schemaChangesInit.InitFromSchemaDifferencesDocument(schemaFile, workspaceName)
    Else
        schemaChangesInit.InitFromSchemaDocument(schemaFile, workspaceName)
    End If
    
    Dim schemaChanges As ISchemaChanges = CType(schemaChangesInit, ISchemaChanges)
    
    ' Print the changes.
    Dim enumSchemaChange As IEnumSchemaChange = schemaChanges.GetChanges()
    PrintSchemaChanges(enumSchemaChange, "")
    
End Sub

Calling the PrintSchemaChanges method

At the end of each procedure, the PrintSchemaChanges method is called. This method, provided with the following code example, prints the schema differences. It is a recursive method that takes an enumeration of schema changes. The enumeration returns objects that implement ISchemaChangeInfo. This interface describes the feature datasets, feature classes, fields, and other schema elements that have changed. It also describes the type of change needed for the target replica to be equivalent to the source replica. Each object can also return an enumeration that further describes the schema changes.
For example, if fields have been added to a feature class in a feature dataset of the source replica, an object is returned to describe that the feature dataset has changed. This object also returns an enumeration that includes an object to describe that the feature class has changed. This in turn, returns an enumeration, which has objects to describe each added field.
[C#]
// Recursive function that steps through the schema changes info.
public void PrintSchemaChanges(IEnumSchemaChange enumSchemaChanges, String
    schemaChange)
{
    enumSchemaChanges.Reset();
    ISchemaChangeInfo schemaChangesInfo = null;
    String dataName = "";

    // Step through the schema changes.
    while ((schemaChangesInfo = enumSchemaChanges.Next()) != null)
    {
        // Get the name of the feature class, feature dataset, and so on, that has changed.
        if (schemaChangesInfo.SchemaChangeType !=
            esriSchemaChangeType.esriSchemaChangeTypeNoChange)
        {
            if (schemaChangesInfo.ToObject != null)
            {
                dataName = GetDataName(schemaChangesInfo.ToObject);
            }
            else if (schemaChangesInfo.FromObject != null)
            {
                dataName = GetDataName(schemaChangesInfo.FromObject);
            }
        }

        // If at the end of the list for the schema change, print the schema change. 
        // Otherwise, continue through the list.
        if (schemaChangesInfo.GetChanges() != null)
        {
            String nextSchemaChange = String.Format("{0}{1}/", schemaChange,
                dataName);
            PrintSchemaChanges(schemaChangesInfo.GetChanges(), nextSchemaChange);
            return ;
        }
        else
        {
            // Convert the schema change type to a string and print the change.
            String changeType = Enum.GetName(typeof(esriSchemaChangeType),
                schemaChangesInfo.SchemaChangeType);
            Console.WriteLine("{0}{1}: {2}", schemaChange, dataName, changeType);
        }
    }
}
[VB.NET]
' Recursive function that steps through the schema changes info.

Public Sub PrintSchemaChanges(ByVal enumSchemaChanges As IEnumSchemaChange, ByVal schemaChange As String)
    
    enumSchemaChanges.Reset()
    Dim schemaChangesInfo As ISchemaChangeInfo = Nothing
    Dim dataName As String = ""
    
    ' Step through the schema changes.
    Do While Not (schemaChangesInfo) Is Nothing
        
        ' Get the name of the feature class, feature dataset, and so on, that has changed.
        If schemaChangesInfo.SchemaChangeType <> esriSchemaChangeType.esriSchemaChangeTypeNoChange Then
            Dim toObject As Object = schemaChangesInfo.ToObject
            Dim fromObject As Object = schemaChangesInfo.FromObject
            If Not toObject Is Nothing Then
                dataName = GetDataName(toObject)
            ElseIf Not fromObject Is Nothing Then
                dataName = GetDataName(fromObject)
            End If
        End If
        
        ' If at the end of the list for the schema change, print the schema change.
        ' Otherwise, continue through the list.
        If Not schemaChangesInfo.GetChanges() Is Nothing Then
            Dim nextSchemaChange As String = String.Format("{0}{1}/", schemaChange, dataName)
            PrintSchemaChanges(schemaChangesInfo.GetChanges(), nextSchemaChange)
            Return
        Else
            ' Convert the schema change type to a string and print the change.
            Dim changeType As String = System.Enum.GetName(GetType(esriSchemaChangeType), schemaChangesInfo.SchemaChangeType)
            Console.WriteLine("{0}{1}: {2}", schemaChange, dataName, changeType)
        End If
        
        schemaChangesInfo = enumSchemaChanges.Next()
        
    Loop
    
End Sub
The following is an example of the output from this method:
BOB.USA_1/BOB.us_counties: esriSchemaChangeTypeDeleteTable
BOB.USA_1/BOB.us_cities: esriSchemaChangeTypeNewTable
BOB.USA_1/BOB.us_states/Field Changes/POP2006: esriSchemaChangeTypeNewField
BOB.USA_1/BOB.us_states/Field Changes/POP2000: esriSchemaChangeTypeDeleteField
BOB.USA_1/BOB.us_states/Field Changes/POP1990: esriSchemaChangeTypeDeleteField
BOB.USA_1/BOB.us_states/Field Changes/POP1996: esriSchemaChangeTypeDeleteField
Each line in the output describes a different schema change. From these results, it is apparent that for the target replica to match the source replica, the following needs to be applied to the target:
  • The us_counties table needs to be deleted.
  • The us_cities table needs to be added.
  • The POP2006 field needs to be added to the us_states table.
  • The POP2000, POP1990, and POP1996 fields need to be deleted from the us_states table.
To apply these changes, augment the PrintSchemaChanges method and set the ISchemaChangeInfo.ApplySchemaChange property for the changes to apply. The ReplicaSchemaImporter is required to import the changes.
The previous PrintSchemaChanges method calls the following utility function. To run this code in applications, be sure to include this function. See the following code example:
[C#]
// Gets the name of the object returned from the schemachangesinfo class.
public String GetDataName(object data)
{
    if (data is IDataElement)
    {
        IDataElement dataElement = (IDataElement)data;
        return dataElement.Name;
    }
    else if (data is IFields)
    {
        return "Field Changes";
    }
    else if (data is IField)
    {
        IField field = (IField)data;
        return field.Name;
    }
    else if (data is IDomain)
    {
        IDomain domain = (IDomain)data;
        return domain.Name;
    }
    else
    {
        return "Unknown type";
    }
}
[VB.NET]
' Gets the name of the object returned from the schemachangesinfo class.

Public Function GetDataName(ByVal data As Object) As String
    
    If TypeOf data Is IDataElement Then
        Dim dataElement As IDataElement = CType(data, IDataElement)
        Dim dataElementName As String = dataElement.Name
        Return dataElementName
    ElseIf TypeOf data Is IFields Then
        Return "Field Changes"
    ElseIf TypeOf data Is IField Then
        Dim field As IField = CType(data, IField)
        Dim fieldName As String = field.Name
        Return fieldName
    ElseIf TypeOf data Is IDomain Then
        Dim domain As IDomain = CType(data, IDomain)
        Dim domainName As String = domain.Name
        Return domainName
    Else
        Return "Unknown type"
    End If
    
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):
Development licensing Deployment licensing
ArcGIS for Desktop Standard ArcGIS for Desktop Standard
ArcGIS for Desktop Advanced ArcGIS for Desktop Advanced
Engine Developer Kit Engine: Geodatabase Update