このトピックでは、マネージ言語を使用して、プロバイダーがメタデータ スキーマを変更するときに Metadata Storage Service ストアをアップグレードする方法について説明します。
このトピックは、C# および Microsoft .NET Framework の概念について基本的な知識がある方を対象としています。
このトピックの例では、次に示す Sync Framework のクラスとインターフェイスを中心に説明します。
メタデータのアップグレードについて
Metadata Storage Service では、簡易データベースにレプリカと項目メタデータを格納します。プロバイダーは、データベースのカスタム フィールドを定義することができます。このフィールドは、開発者が新しいバージョンのプロバイダーをリリースしたときに変更される可能性があるものです。Sync Framework では、プロバイダー バージョンの変更によるメタデータ ストアのアップグレードをサポートしています。
メタデータ ストアのアップグレードが必要になるのは、プロバイダーが使用するカスタム フィールドが変更されるときだけです。項目データの形式を変更しても、メタデータの形式は影響を受けません。
プロバイダーは、レプリカ メタデータを格納するときに ProviderVersion を使用して、レプリカ メタデータと互換性のあるプロバイダー バージョンを設定します。プロバイダーは、後でメタデータ ストアを開くとき、レプリカ メタデータに関連付けられたプロバイダー バージョンをチェックすることができます。メタデータ ストアを開くプロバイダーのバージョンと、メタデータ内に格納されているプロバイダー バージョンが異なる場合、プロバイダーではレプリカのメタデータ スキーマをアップグレードすることができます。
メタデータ ストアは、次の手順でアップグレードされます。
SqlSyncMetadataStoreSerializer オブジェクトを使用して、レプリカ メタデータが初期化されます。
レプリカ メタデータが、メタデータ ストアから削除されます。
レプリカ メタデータが、新しい形式でメタデータ ストアに作成されます。
シリアル化済みのレプリカ メタデータが、SqlSyncMetadataStoreSerializer オブジェクト使用して新しい形式にインポートされます。
Sync Framework にはコールバック機構 IProviderUpgradeCallback が用意されているので、プロバイダーは、必要に応じてメタデータを変更することも含めたアップグレード プロセスを制御することができます。
詳細については、「メタデータ ストアのアップグレード」を参照してください。
ビルド要件
.NET Framework 2.0 以上
例
このトピックのコード例では、アップグレード時にカスタム フィールドを追加するメタデータ ストアをアップグレードする方法を示します。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 のバージョンが変更されたときにメタデータ ストアをアップグレードする方法について学習することをお勧めします。詳細については、「メタデータ ストアのアップグレード」を参照してください。
また、メタデータ ストアの正規の形式を使用して、メタデータ ストアをアップグレードせずに異なるバージョンのコンポーネントが互いに連携できるようにする方法についても学習することをお勧めします。詳細については、「バージョンが異なるコンポーネントのメタデータへのアクセス」を参照してください。