共用方式為


HOW TO:在提供者變更中繼資料結構描述時升級中繼資料

本主題描述如何使用 Managed 語言,在提供者變更中繼資料結構描述時升級中繼資料儲存服務存放區。

本主題假設您對於 C# 和 Microsoft .NET Framework 概念有基本的了解。

本主題的範例將重點放在下列 Sync Framework 類別和介面:

了解中繼資料升級

中繼資料儲存服務會將複寫和項目中繼資料儲存在輕量型資料庫中。提供者可以在資料庫中定義自訂欄位,而這些自訂欄位可能會在開發人員發行特定提供者的新版本時變更。Sync Framework 支援由於提供者版本變更而升級中繼資料存放區的作業。

只有當提供者所使用的自訂欄位變更時,才需要進行中繼資料存放區升級。變更項目資料的格式並不會影響中繼資料的格式。

當提供者儲存複寫的中繼資料時,它就會使用 ProviderVersion 來設定與複寫中繼資料相容的提供者版本。當提供者之後開啟中繼資料存放區時,它可以檢查與複寫中繼資料相關聯的提供者版本。當開啟中繼資料存放區的提供者版本與儲存於中繼資料的提供者版本不同時,此提供者可以升級複寫的中繼資料結構描述。

中繼資料存放區是使用下列步驟來升級的。

  1. SqlSyncMetadataStoreSerializer 物件用來序列化複寫中繼資料。

  2. 從中繼資料存放區中移除複寫中繼資料。

  3. 在中繼資料存放區中建立採用新格式的複寫中繼資料。

  4. 使用 SqlSyncMetadataStoreSerializer 物件,將先前序列化的複寫中繼資料匯入新格式。

Sync Framework 會提供一項回呼機制 IProviderUpgradeCallback,讓提供者控制升級程序,包括對中繼資料進行任何必要的變更。

如需詳細資訊,請參閱升級中繼資料存放區版本

組建需求

範例

本主題的範例程式碼將示範如何升級在升級期間新增自訂欄位的中繼資料存放區。實作 IProviderUpgradeCallback 的類別是用來針對中繼資料存放區中的每個項目設定新欄位的值。

升級中繼資料存放區

這則範例會在複寫中繼資料的目前提供者版本小於指定的值時,升級中繼資料存放區。在升級期間,有一個額外的自訂欄位會新增至複寫的中繼資料結構描述並指定為索引欄位。

請注意,您必須處置並重新開啟 SqlMetadataStore 物件,才能釋放 ReplicaMetadata 物件的所有參考。如果沒有這樣做,RemoveReplicaMetadata 的呼叫就會擲回 ReplicaMetadataInUseException

public static void UpgradeMetadataStore(SqlMetadataStore store, string storePath,
    SortedList<SyncId, Contact> contactList)
{
    // Get the provider version and replica ID from the metadata store.
    uint providerVersion = store.GetSingleReplicaMetadata().ProviderVersion;
    SyncId replicaId = store.GetSingleReplicaMetadata().ReplicaId;

    // Check the provider version of the metadata store and upgrade if necessary.
    if (providerVersion < (uint)ContactsProviderVersion.ContactsProvider_v2)
    {
        // Dispose the store to release all references to the replica metadata
        // or the call to RemoveReplicaMetadata will throw ReplicaMetadataInUseException.
        store.Dispose();
        store = null;

        // Reopen the store.
        store = SqlMetadataStore.OpenStore(storePath);

        // Start a transaction.
        store.BeginTransaction();

        // Serialize the metadata store in canonical format.
        string serializedName = "SerializedStoreForUpgrade.dat";
        SyncMetadataStoreSerializer mdsSerializer = store.GetMetadataStoreSerializer();
        mdsSerializer.SerializeReplicaMetadata(ContactStore.ContactIdFormatGroup, replicaId,
            serializedName, CompatibilityLevel.SyncFrameworkVersion1);
        
        // Remove the replica metadata from the store.
        store.RemoveReplicaMetadata(ContactStore.ContactIdFormatGroup, replicaId);

        // Initialize replica metadata, adding a new index column for Address.

        // Create custom fields for First Name, Last Name, Phone Number. These will be used
        // as unique index fields for identifying items between the metadata store and the item store.
        // Also include a custom field for Address, which will be used as an index.
        FieldSchema[] CustomFields = 
        {
            new FieldSchema(FirstNameField, typeof(string), 100),
            new FieldSchema(LastNameField, typeof(string), 100),
            new FieldSchema(PhoneNumberField, typeof(string), 20),
            new FieldSchema(AddressField, typeof(string), 100)
        };

        // Specify the index fields.
        string[] IndexFields = { FirstNameField, LastNameField, PhoneNumberField };
        IndexSchema[] Indexes = 
        {
            new IndexSchema(IndexFields, true),
            new IndexSchema(AddressField, false)
        };

        // Create the metadata for the replica in the metadata store.
        ReplicaMetadata newRepMeta = store.InitializeReplicaMetadata(
            ContactIdFormatGroup, replicaId, CustomFields, Indexes);

        // Import the serialized metadata.
        ContactsProviderUpgrader upgrader = new ContactsProviderUpgrader(contactList);
        mdsSerializer.DeserializeReplicaMetadata(serializedName, (uint)ContactsProviderVersion.ContactsProvider_v2,
            upgrader);

        // Set the new provider version.
        newRepMeta.ProviderVersion = (uint)ContactsProviderVersion.ContactsProvider_v2;

        newRepMeta.SaveReplicaMetadata();

        // Commit the transaction.
        store.CommitTransaction();
    }
}

回應升級回呼

這則範例會定義實作 IProviderUpgradeCallback 介面的類別。在上一則範例中,這個類別的執行個體會指定給 DeserializeReplicaMetadata 方法。Sync Framework 會呼叫這個介面中的方法,讓提供者控制升級並且對中繼資料進行任何必要的變更。在這則範例的 OnProviderUpgradeRequired 方法中,如果目前儲存在複寫中繼資料內的提供者版本不是預期的值,就會取消升級。在這則範例的 OnItemMetadataDeserialized 方法中,新 address 欄位的值會設定於每個項目的中繼資料內。

class ContactsProviderUpgrader : IProviderUpgradeCallback
{
    // The contact list is the item store. Save it so new metadata fields can be updated
    // during the upgrade.
    public ContactsProviderUpgrader(SortedList<SyncId, Contact> contactList) 
    {
        _contactList = contactList;
    }

    private SortedList<SyncId, Contact> _contactList;

    #region IProviderUpgradeCallback Members

    public void OnCustomReplicaMetadataDeserialized(byte[] customReplicaMetadata)
    {
        // This replica doesn't store custom replica metadata, so there's nothing to do!
    }

    public void OnItemMetadataDeserialized(ItemMetadata itemMetadata, Dictionary<string, SyncFieldValue> extraFields)
    {
        // The address field is new in the upgrade, so set it now from the contact list.
        Contact contact = _contactList[itemMetadata.GlobalId];
        itemMetadata.SetCustomField(ContactStore.AddressField, contact.Address);
    }

    public void OnProviderUpgradeRequired(uint dwCurrentProviderVersionInFile)
    {
        // This upgrader can only upgrade from provider version 1.
        if ((uint)ContactsProviderVersion.ContactsProvider_v1 != dwCurrentProviderVersionInFile)
        {
            throw new MetadataStoreProviderVersionMismatchException("Can't upgrade the metadata store from the specified version.");
        }
    }

後續的步驟

接著,您可能會想要深入了解如何在 Sync Framework 的版本變更時升級中繼資料存放區。如需詳細資訊,請參閱升級中繼資料存放區版本

此外,您可能也會想要深入了解如何使用中繼資料存放區的標準格式,讓不同版本的元件相互溝通,而不升級中繼資料存放區。如需詳細資訊,請參閱從不同版本的元件存取中繼資料

請參閱

概念

程式設計一般標準的自訂提供者工作
升級中繼資料存放區版本