C#でDataverseのテーブルのフォームを更新してみた

# はじめに
PowerAppsのモデル駆動の設定が面倒なのでC#からDataverseを操作してみたくなった。
今回はdataverseにテーブルに定義されているフォームを更新するC#コードを実行してみる。

# 前提
参照ライブラリやCreateCrmService関数の中身は以前の以下の記事を参考に

C#でDataverseに接続してテーブル一覧を表示してみた
https://qiita.com/akihiroe_/items/2db8e2634d7962ef0df7

# 注意
以下のコードはdataverse上のシステムが管理しているテーブルのデータを直接変更しています。予期せぬ副作用が発生する可能性があるかもしれませんので、留意お願いします。

# コード
dataverseのテーブルのフォームの情報はsystemformテーブルに格納されています。そして、このテーブルの属性のFormXmlにビューのレイアウト情報が格納されています。それらを更新することでフォームを更新できそうです。
以下のコードではフォームの名前項目を新名前項目に変更し、読み取り専用にしています。

```C#
var organizationService = CreateCrmService(user, password, url);

var tableName = "systemform";
var id = Guid.Parse("xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
var columns = new string[] { "name", "formxml" };
var entity = organizationService.Retrieve(tableName, id, new ColumnSet(columns));

var formxml = XDocument.Parse((string)entity.Attributes["formxml"]);
Console.WriteLine(formxml);

var label = formxml.Descendants("label").First(x => x.Attribute("description").Value == "名前");
label.Attribute("description").Value = "新名前";

var control = formxml.Descendants("control").First(x => x.Attribute("datafieldname").Value == "test_name");
control.Add(new XAttribute("disabled", "true"));

entity.Attributes["formxml"] = formxml.ToString();
organizationService.Update(entity);
```
*idは該当フォームのデザイナーをWeb画面で表示したURLのform/edit/以降のGUIDを指定する
https://make.powerapps.com/.../form/edit/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx?...

# フォームXMLのサンプル
以下はテーブルを作成すると自動的に作成される情報のフォームのXMLです。名前と所有者の２つの項目があります。構造的にはタブがあって１つのタブがセクションで分割されその中にテーブルのセルに各項目を配置するような構造になっています。
見出しはlabelノード、コントロールはcontrolノードになっていています。controlタグにはclassid属性でコントロールの種類、対応する項目名をdatafieldname属性で指定している構造のようです。
```xml
<form>
  <tabs>
    <tab verticallayout="true" id="{432ccc8e-56a3-434b-b51f-49e183d848e4}" IsUserDefined="1">
      <labels>
        <label description="全般" languagecode="1041" />
      </labels>
      <columns>
        <column width="100%">
          <sections>
            <section showlabel="false" showbar="false" IsUserDefined="0" id="{25634bb7-d4df-41ef-ac2c-1bb4858db80a}">
              <labels>
                <label description="全般" languagecode="1041" />
              </labels>
              <rows>
                <row>
                  <cell id="{fc38ef90-791b-4010-a0d2-30e66b5f107a}">
                    <labels>
                      <label description="名前" languagecode="1041" />
                    </labels>
                    <control id="test_name" classid="{4273EDBD-AC1D-40d3-9FB2-095C621B552D}" datafieldname="test_name" />
                  </cell>
                </row>
                <row>
                  <cell id="{a1aa9de0-f964-4c76-8fa7-2d04da91dc55}">
                    <labels>
                      <label description="所有者" languagecode="1041" />
                    </labels>
                    <control id="ownerid" classid="{270BD3DB-D9AF-4782-9025-509E298DEC0A}" datafieldname="ownerid" />
                  </cell>
                </row>
              </rows>
            </section>
          </sections>
        </column>
      </columns>
    </tab>
  </tabs>
</form>
```
*labelのlableidは全てフォームを重複しないGuidにしないといけないようです。他のフォームにXMLをコピーしてlabelidが重なると一方の文言を修正すると同じlableidのlableの表示も影響を受けるようです。内部的に管理している可能性があります。あとソリューションのエクスポート時にもエラーになりますので新しいGuidを割り当てる必要はあるようです。

classidの一覧です。他にもありそうですが主なものです。
|classid |コントロール| 
|---|---|
|{67FAC785-CD58-4F9F-ABB3-4B7DDC6ED5ED}|はい/いいえ|
|{B0C6723A-8503-4Fd7-BB28-C8A06AC933C2}|Checkbox|
|{E0DECE4B-6FC8-4A8F-A065-082708572369}|テキストエリア|
|{4273EDBD-AC1D-40D3-9FB2-095C621B552D}|テキスト|
|{5B773807-9FB2-42DB-97C3-7A91EFF8ADFF}|日付|
|{ADA2203E-B4CD-49BE-9DDF-234642B43B52}|メール|
|{8C10015A-B339-4982-9474-A95FE05631A5}|電話|
|{71716B6C-711E-476C-8AB8-5D11542BFB47}|URL|
|{E7A81278-8635-4D9E-8D4D-59480B391C5B}|サブグリッド|
|{3EF39988-22BB-4F0B-BBBE-64B5A3748AEE}|オプションセット|
|{270BD3DB-D9AF-4782-9025-509E298DEC0A}|参照|


# おわりに
フォームの定義もdataverseのレコードと処理できるので、画面上の項目名を一括変換とかできそうです。
１つづつフォームのデザイナを開けて修正する作業は辛いですからね。:sweat:

# 参照情報
https://learn.microsoft.com/ja-jp/power-apps/developer/model-driven-apps/form-xml-schema