Dynamics CRM 2016 SDK 新機能: メタデータ Web API その 3: 関連

みなさん、こんにちは。

前回に引き続き、Dynamics CRM 2016 SDK の新機能として正式版と
なった Web API について紹介します。

今回は Web API メタデータサービスの機能より、関連のメタデータ
操作を紹介します。

概要

既存の組織サービス同様、Web API を利用してメタデータを操作する
ことが可能です。サポートされる操作は多岐に渡りますが、今回は
関連の操作を紹介します。

1:N 関連の作成

まずは取引先企業と取引先担当者の間に、カスタム 1:N 関連を作成
してみます。

プログラムの実装

1. 前回利用した Visual Studio ソリューションを開き、Program.cs
ファイルを開きます。新しく以下のメソッドを追加します。

public async Task RunRelationshipMetadata(string accessToken)
{
    // HttpClient の作成
    using (HttpClient httpClient = new HttpClient())
    {
        //  Web API アドレスの作成
        string serviceUrl = serverUrl + "/api/data/v8.0/";
        // ヘッダーの設定
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);

    }
}

2. Main メソッドの以下のコードを書き換えて、新しいメソッドを
呼ぶように変更します。

元)  
Task.WaitAll(Task.Run(async () => await app.RunFieldMetadata(result.AccessToken)));

変更後)
Task.WaitAll(Task.Run(async () => await app.RunRelationshipMetadata(result.AccessToken)));

3. 新しく追加した RunRelationshipMetadata メソッド内に以下のコードを
追加して、1:N 関連の情報を作成します。

// 1:N 関連の情報を作成
string customRelationshipMeta = @"
{
    '@odata.type': '#Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata',
    'AssociatedMenuConfiguration': {
        'Behavior': 'UseCollectionName',
        'Group': 'Details',
        'Label': {
            'LocalizedLabels': [],
            'UserLocalizedLabel': null
        },
        'Order': 10000
    },
    'CascadeConfiguration': {
        'Assign': 'NoCascade',
        'Delete': 'RemoveLink',
        'Merge': 'Cascade',
        'Reparent': 'NoCascade',
        'Share': 'NoCascade',
        'Unshare': 'NoCascade'
    },
    'ReferencedEntity': 'account',
    'ReferencingEntity': 'contact',
    'SchemaName': 'new_account_contacts',
    'Lookup': {
        'SchemaName':'new_accountId',
        'DisplayName': {
            'LocalizedLabels': [{
                'Label': 'サンプル取引先企業',
                'LanguageCode': 1041
            }],
            'UserLocalizedLabel': {
                'Label': 'サンプル取引先企業',
                'LanguageCode': 1041
            }
        }
    }
}";

4. 以下のコードを追加して作成要求を送信します。

// カスタム 1:N 関連の作成
HttpResponseMessage createRes = await httpClient.PostAsync(serviceUrl + "RelationshipDefinitions",
    new StringContent(customRelationshipMeta, Encoding.UTF8, "application/json"));

動作確認

1. F5 キーを押下してプログラムを実行します。

2. 認証ダイアログが表示されたらログインします。

image

3. プログラム完了後、カスタム 1:N 関連が作成されて
いることを確認します。

image

関連の取得: システムレベル

次に作成した関連を取得します。関連はシステム全体からでも、特定
エンティティからでも取得できます。次の作業にあたり上記で追加した
1:N 関連の作成要求はコメントアウトしておきます。

プログラムの実装

1. 上記のコードに続いて以下のコードを追加します。ここではシステム
全体から特定の 1:N 関連を取得しています。

// 作成した関連をシステムレベルから取得
HttpResponseMessage relationshipRes = await httpClient.GetAsync(serviceUrl + "RelationshipDefinitions?$filter=SchemaName eq 'new_account_contacts'");
JToken relationship = JObject.Parse(relationshipRes.Content.ReadAsStringAsync().Result)["value"][0];

2. 以下のコードを追加して結果を表示します。

// 詳細を表示
Console.WriteLine(relationship);

動作確認

1. F5 キーを押下してプログラムを実行します。

2. 認証ダイアログが表示されたらログインします。

3. 関連の詳細が表示されます。

image

関連の取得: エンティティレベル

次に取引先企業のメタデータから関連を取得します。

プログラムの実装

1. 上記のコードに続いて以下のコードを追加して、取引先企業の
メタデータ ID を取得します。

// 取引先企業エンティティの取得
HttpResponseMessage entityRes = await httpClient.GetAsync(serviceUrl + "EntityDefinitions?$select=MetadataId&$filter=LogicalName eq 'account'");
JToken entity = JObject.Parse(entityRes.Content.ReadAsStringAsync().Result)["value"][0];

2. 以下のコードを追加して関連を取得します。エンティティの
メタデータから /OneToManyRelationships ナビゲーションで
1:N 関連を取得できます。

// 関連をエンティティレベルから取得
HttpResponseMessage relationshipRes2 = await httpClient.GetAsync(serviceUrl + "EntityDefinitions(" + entity["MetadataId"] + ")/OneToManyRelationships?$filter=SchemaName eq 'new_account_contacts'");
JToken relationship2 = JObject.Parse(relationshipRes2.Content.ReadAsStringAsync().Result)["value"][0];

3. 以下のコードを追加して結果を表示します。

// 詳細を表示
Console.WriteLine(relationship2);

動作確認

1. F5 キーを押下してプログラムを実行します。

2. 認証ダイアログが表示されたらログインします。

3. 関連の詳細が表示されます。

関連の削除

更新および削除も通常のレコード同様に行えます。ここでは削除の
方法を紹介します。

プログラムの実装

上記のコードに続いて以下のコードを追加します。レコードの ID に
相当するものとして、MetadataId があります。これを取得した内容から
取り出して、指定しています。

// 作成した関連の削除
HttpResponseMessage deleteRes = await httpClient.DeleteAsync(serviceUrl + "RelationshipDefinitions(" + relationship["MetadataId"] + ")");

動作確認

1. F5 キーを押下してプログラムを実行します。

2. 認証ダイアログが表示されたらログインします。

3. 作成した 1:N 関連が削除されることを確認します。

N:N 関連の作成

N:N 関連の作成も基本的には同じ手法で行いますが、以下の点が
異なります。

作成時に指定するタイプ:
"@odata.type": "Microsoft.Dynamics.CRM.ManyToManyRelationshipMetadata"

エンティティメタデータからのナビゲーション
EntityDefinitions(<MetadataId>/ManyToManyRelationships

以下に今回追加したメソッドを示します。

public async Task RunRelationshipMetadata(string accessToken)
{
    // HttpClient の作成
    using (HttpClient httpClient = new HttpClient())
    {
        //  Web API アドレスの作成
        string serviceUrl = serverUrl + "/api/data/v8.0/";
        // ヘッダーの設定
        httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
                               
        // 1:N 関連の情報を作成
        string customRelationshipMeta = @"
        {
            '@odata.type': '#Microsoft.Dynamics.CRM.OneToManyRelationshipMetadata',
            'AssociatedMenuConfiguration': {
                'Behavior': 'UseCollectionName',
                'Group': 'Details',
                'Label': {
                    'LocalizedLabels': [],
                    'UserLocalizedLabel': null
                },
                'Order': 10000
            },
            'CascadeConfiguration': {
                'Assign': 'NoCascade',
                'Delete': 'RemoveLink',
                'Merge': 'Cascade',
                'Reparent': 'NoCascade',
                'Share': 'NoCascade',
                'Unshare': 'NoCascade'
            },
            'ReferencedEntity': 'account',
            'ReferencingEntity': 'contact',
            'SchemaName': 'new_account_contacts',
            'Lookup': {
                'SchemaName':'new_accountId',
                'DisplayName': {
                    'LocalizedLabels': [{
                        'Label': 'サンプル取引先企業',
                        'LanguageCode': 1041
                    }],
                    'UserLocalizedLabel': {
                        'Label': 'サンプル取引先企業',
                        'LanguageCode': 1041
                    }
                }
            }
        }";

        // カスタム 1:N 関連の作成
        HttpResponseMessage createRes = await httpClient.PostAsync(serviceUrl + "RelationshipDefinitions",
            new StringContent(customRelationshipMeta, Encoding.UTF8, "application/json"));

        // 作成した関連をシステムレベルから取得
        HttpResponseMessage relationshipRes = await httpClient.GetAsync(serviceUrl + "RelationshipDefinitions?$filter=SchemaName eq 'new_account_contacts'");
        JToken relationship = JObject.Parse(relationshipRes.Content.ReadAsStringAsync().Result)["value"][0];

        // 詳細を表示
        Console.WriteLine(relationship);

        // 取引先企業エンティティの取得
        HttpResponseMessage entityRes = await httpClient.GetAsync(serviceUrl + "EntityDefinitions?$select=MetadataId&$filter=LogicalName eq 'account'");
        JToken entity = JObject.Parse(entityRes.Content.ReadAsStringAsync().Result)["value"][0];

        // 関連をエンティティレベルから取得
        HttpResponseMessage relationshipRes2 = await httpClient.GetAsync(serviceUrl + "EntityDefinitions(" + entity["MetadataId"] + ")/OneToManyRelationships?$filter=SchemaName eq 'new_account_contacts'");
        JToken relationship2 = JObject.Parse(relationshipRes2.Content.ReadAsStringAsync().Result)["value"][0];

        Console.WriteLine(relationship2);

        // 作成した関連の削除
        HttpResponseMessage deleteRes = await httpClient.DeleteAsync(serviceUrl + "RelationshipDefinitions(" + relationship["MetadataId"] + ")");
    }
}

まとめ

次回はオプションセットについて紹介します。
お楽しみに!

- 中村 憲一郎

※本情報の内容(添付文書、リンク先などを含む)は、作成日時点でのものであり、予告なく変更される場合があります