Managing Metadata for Simple Providers

A simple provider requires that you store metadata in metadata storage services, which is implemented in SqlMetadataStore (for managed code) and ISqlSyncMetadataStore (for unmanaged code).

The metadata store contains the following types of metadata with which a provider or application will interact:

  • A replica ID. This identifies the replica that uses a particular store.

  • Item IDs and versions. These identify each item that has been enumerated from an item store and the current version of that item.

  • Change unit IDs and versions. These optionally identify parts of an item that need to be tracked and the current version of each part. For example, a contact in a contact database could be an item, and the phone number field could be one of the change units.

Identifying Items in the Item Store and Metadata Store

To synchronize an item, Sync Framework must be able to identify the item in the item store and map that identity to an internal ID in the metadata store. It must also be able to determine if the item version has changed since the last synchronization session. If the version has changed and the destination replica does not already contain that version of an item, the item should be synchronized. If changes are synchronized at the level of a change unit instead of an item, Sync Framework must be able to identify the change unit and its version. A change unit represents a sub-item change, such as the telephone number field in an item that represents a contact. This sample does not use change units.

Specifying the Format of Metadata Store IDs

The following code defines the constructor for MyFullEnumerationSimpleSyncProvider and the IdFormats property. This enables the Sync Framework runtime to determine what format the metadata store uses for IDs. If flexible IDs are not used, Sync Framework uses a fixed format to identify replicas, items, and change units. If flexible IDs are used, ISimpleSyncProviderIdGenerator methods are used to generate IDs.

public MyFullEnumerationSimpleSyncProvider(string name, MySimpleDataStore store)
    _name = name;
    _store = store;

    // Create a file to store metadata for all items and a file to store 
    // the replica ID.
    _replicaMetadataFile = Environment.CurrentDirectory + "\\" + _name.ToString() + ".Metadata";
    _replicaIdFile = Environment.CurrentDirectory + "\\" + _name.ToString() + ".Replicaid";

    // Set ReplicaIdFormat to use a GUID as an ID, and ItemIdFormat to use a GUID plus
    // an 8-byte prefix.
    _idFormats = new SyncIdFormatGroup();
    _idFormats.ItemIdFormat.IsVariableLength = false;
    _idFormats.ItemIdFormat.Length = 24;
    _idFormats.ReplicaIdFormat.IsVariableLength = false;
    _idFormats.ReplicaIdFormat.Length = 16;

    this.ItemConstraint += new EventHandler<SimpleSyncItemConstraintEventArgs>(OnItemConstraint);
    this.ItemConflicting += new EventHandler<SimpleSyncItemConflictingEventArgs>(OnItemConflicting);

public SyncId ReplicaId
        if (_replicaId == null)
            _replicaId = GetReplicaIdFromFile( _replicaIdFile);

        return _replicaId; 

public override SyncIdFormatGroup IdFormats
    get { return _idFormats; }

Public ReadOnly Property ReplicaId() As SyncId
        If _replicaId Is Nothing Then
            _replicaId = GetReplicaIdFromFile(_replicaIdFile)
        End If

        Return _replicaId
    End Get
End Property

Public Overrides ReadOnly Property IdFormats() As SyncIdFormatGroup
        Return _idFormats
    End Get
End Property

Specifying Item Fields and the Metadata Schema

Sync Framework maps item store data, or additional metadata that you create, to internal metadata store IDs and versions by using an ItemMetadataSchema object that is exposed by the MetadataSchema property. The following code examples provide input for the ItemMetadataSchema object. The constants in the sample code define an integer value for each column in the item store. These values are used when creating the custom field definitions and identity rules for the ItemMetadataSchema object.

public const uint CUSTOM_FIELD_ID = 1;
public const uint CUSTOM_FIELD_TIMESTAMP = 2;

public override ItemMetadataSchema MetadataSchema
        CustomFieldDefinition[] customFields = new CustomFieldDefinition[2];
        customFields[0] = new CustomFieldDefinition(CUSTOM_FIELD_ID, typeof(ulong));
        customFields[1] = new CustomFieldDefinition(CUSTOM_FIELD_TIMESTAMP, typeof(ulong));

        IdentityRule[] identityRule = new IdentityRule[1];
        identityRule[0] = new IdentityRule(new uint[] { CUSTOM_FIELD_ID });

        return new ItemMetadataSchema(customFields, identityRule);

Public Overrides ReadOnly Property MetadataSchema() As ItemMetadataSchema
        Dim customFields As CustomFieldDefinition() = New CustomFieldDefinition(1) {}
        customFields(0) = New CustomFieldDefinition(CUSTOM_FIELD_ID, GetType(ULong))
        customFields(1) = New CustomFieldDefinition(CUSTOM_FIELD_TIMESTAMP, GetType(ULong))

        Dim identityRule As IdentityRule() = New IdentityRule(0) {}
        identityRule(0) = New IdentityRule(New UInteger() {CUSTOM_FIELD_ID})

        Return New ItemMetadataSchema(customFields, identityRule)
    End Get
End Property

The ItemMetadataSchema object exposes three properties:

  • CustomFields

    Custom fields are fields in the metadata store that are identified by integers. If an application requires a friendly name for one or more fields, it should map the integer to a name. Custom fields are defined for two reasons: to identify items, and to provide version information about those items. Version fields enable Sync Framework to determine if an item or change unit has changed. In this example, the version fields contain the actual data from the item store, so there is a field for each field in the item store. This one-to-one correspondence is not required, nor is it efficient. A more practical solution would be to take a hash of the item fields and store that in a single custom field.

  • IdentityRules

    The identity rule specifies which custom field or fields should be used to identify an item. In this case, the CUSTOM_FIELD_ID field (field 0) is used.

  • ChangeUnitVersionDefinitions (not used in this sample)

    If change units are used, you must define version fields for the change units. There is no requirement that there be a one-to-one mapping between change units and version information, or that the actual data must be stored. Change units can also span multiple fields. For example, this application could specify that Zip and Phone are a change unit and that Guid is another change unit. For Guid, you might use the actual data, and for the other change unit a hash of the Zip and Phone fields or some other mechanism to determine version.

Some of the methods that work with item store data, such as InsertItem, require a collection of ItemField objects that represent each field. The ItemFieldDictionary objects that are parameters to these methods have the same index values as those specified in the CustomFieldDefinition objects.

See Also