データ エンティティの列と仮想フィールドを計算する

コミュニティの関心グループが Yammer から Microsoft Viva Engage に移行されました。 Viva Engage コミュニティに参加し、最新のディスカッションに参加するには、「 Finance and Operations Viva Engage Community へのアクセスを要求する 」フォームに入力し、参加するコミュニティを選択します。

この記事では、計算されたフィールドと仮想フィールドに関する情報を提供します。これは、データ エンティティが持つことができる 2 つのタイプのマッピングされていないフィールドです。 マップされていないフィールドのプロパティに関する情報と、フィールドを作成、使用、テストする方法を示す例が含まれています。

このサンプル コードは、所有するソリューションの一部であるエンティティを作成または変更することを目的としています。 既存のエンティティを拡張するには、若干の変更を加える必要があります。

概要

データ エンティティは、データ ソースのフィールドに直接マップされているフィールド以外にマップされていないフィールドを追加で持つことができます。 マップされていないフィールドの値は、次の 2 つのメカニズムを使用して生成できます。

  • カスタム X++ コード
  • Microsoft SQL Server で実行される SQL

マップされていない2種類のフィールドは、計算と仮想です。 マップされていないフィールドは常に読み取り操作をサポートしますが、機能仕様では、書き込み操作をサポートするための開発作業は必要とされない場合があります。

計算フィールド

  • SQL ビューの計算列で値が生成されます。
  • データを読み取る際に、SQL はデータを処理し、ビューから直接取得します。
  • 書き込みの場合、カスタム X++ コードは入力値を解析し、解析された値をデータ エンティティの通常のフィールドに書き込みます。 値はエンティティのデータ ソースの通常のフィールドに格納されます。
  • 主に読み取りに計算フィールドを使用します。
  • 可能であれば、計算列は SQL Server レベルで計算されるため、仮想フィールドの代わりに計算列を使用します。一方、仮想フィールドは X++ の計算行ごとに計算されます。

仮想フィールド

  • 保持されないフィールドです。
  • カスタム X++ コードによって制御されます。
  • 読み取り/書き込みは、カスタム X++ コードを通じて発生します。
  • X++ コードを使用して計算され、計算列に置き換えることができない取り込み値には仮想フィールドを使用します。
  • 仮想フィールドでの検索とフィルター処理はサポートされていません。

マップされていないフィールドのプロパティ

カテゴリ 氏名 タイプ 既定値 動作
データ IsComputedField NoYes はい
  • はい: - フィールドは、SQL ビューの計算済み列として同期されます。 列の SQL 定義文字列を計算するために X++ メソッドが必要です。 仮想列の定義は静的であり、エンティティが同期されているときに使用されます。 その後は、X++ メソッドは、実行時に呼び出されません。
  • いいえ - フィールドは、入庫および出荷の値がカスタム コードによって完全に制御される真の仮想フィールドです。
データ ComputedFieldMethod 文字列 フィールド定義を生成する SQL 式を構築するための X++ の静的 な DataEntity メソッド。 プロパティ IsComputedFieldいいえ に設定されている場合、このプロパティは無効で無関係です。 このメソッドは、プロパティ IsComputedFieldはい に設定されている場合に必要です。
データ ExtendedDataType 文字列

例: 計算フィールドを作成

この例では、FMCustomerEntity エンティティに計算フィールドを追加します。 読み取りの場合、フィールドは顧客の名前と住所を書式設定された文字列に結合します。 書き込みについては、X++ コードは複合値を個別の名前および住所の値に解析し、それからコードが通常の名前や住所フィールドを更新します。

  1. Microsoft Visual Studio で、プロジェクトを右クリックし、既存の FMCustomerEntity を追加します。

  2. ソリューション エクスプローラーで、 FMCustomerEntity ノードを右クリックし、[ 開く] を選択します。

  3. FMCustomerEntity のデザイナーで、[フィールド] ノードを右クリックし、[新規作成]、[文字列のマップ解除>フィールド] の順に選択します。

    マップされていない新しい文字列フィールドの作成のスクリーンショット。

  4. 新しいフィールドの名前を NameAndAddress に変更します。

  5. 次のスクリーンショットに示すように、マッピングされていない NameAndAddress フィールドのプロパティを更新します。

    NameAndAddress のマップされていないフィールドのプロパティを更新するスクリーンショット。

  6. FMCustomerEntity>メソッドに移動します。 [メソッド] ノードを右クリックし、[新規] を選択します。 メソッド名が、マップされていない計算されたフィールドの DataEntityView方法 のプロパティ値と一致していることを、確認します。

  7. 次の X++ コードをメソッドに貼り付けます。 このメソッドは、結合されて書式設定された NameAndAddress 値を返します。

    private static str formatNameAndAddress()   // X++
    {
        DataEntityName      dataEntityName= tablestr(FMCustomerEntity);
        List                fieldList = new List(types::String);
        ////Format name and address to look like following
        ////John Smith, 123 Main St, Redmond, WA 98052
        fieldList.addEnd(SysComputedColumn::returnField(DataEntityName, identifierstr(FMCustomer), fieldstr(FMCustomer, FirstName)));
        fieldList.addEnd(SysComputedColumn::returnLiteral(" "));
        fieldList.addEnd(SysComputedColumn::returnField(DataEntityName, identifierstr(FMCustomer), fieldstr(FMCustomer, LastName)));
        fieldList.addEnd(SysComputedColumn::returnLiteral("; "));
        fieldList.addEnd(SysComputedColumn::returnField(DataEntityName, identifierstr(FMAddressTable), fieldstr(FMAddressTable, AddressLine1)));
        fieldList.addEnd(SysComputedColumn::returnLiteral(", "));
        fieldList.addEnd(SysComputedColumn::returnField(DataEntityName, identifierstr(FMAddressTable), fieldstr(FMAddressTable, City)));
        fieldList.addEnd(SysComputedColumn::returnLiteral(", "));
        fieldList.addEnd(SysComputedColumn::returnField(DataEntityName, identifierstr(FMAddressTable), fieldstr(FMAddressTable, State)));
        fieldList.addEnd(SysComputedColumn::returnLiteral(", "));
        fieldList.addEnd(SysComputedColumn::cast(
            SysComputedColumn::returnField(DataEntityName, identifierstr(FMAddressTable), fieldstr(FMAddressTable, ZipCode)), "NVARCHAR"));
        return SysComputedColumn::addList(fieldList);
    }
    
    T-SQL for the computed column.
    
    ( Cast (( ( T1.firstname ) + ( N' ' ) + ( T1.lastname ) + ( N'; ' ) +
        ( T5.addressline1 )
        + ( N', ' ) + ( T5.city ) + ( N', ' ) + ( T5.state ) + (
        N', '
        ) +
        ( Cast(T5.zipcode AS NVARCHAR) ) ) AS NVARCHAR(100))
    )
    AS
    NAMEANDADDRESS
    

    ヒント

    計算列が原因でデータ エンティティの同期でエラーが発生した場合は、X++ で使用する前に、Microsoft SQL Server Management Studio (SSMS) で SQL 定義を作成する方が簡単です。

  8. プロジェクトをリビルドします。

  9. データベースを同期させます。 この手順を忘れないでください。 Dynamics 365 > データベースの同期 > 同期に移動することによりこれを実行することができます。

例: 仮想フィールドを作成

この例では、FMCustomerEntity エンティティに仮想フィールドを追加します。 このフィールドには、姓と名の組み合わせとしてフルネームが表示されます。 X++ コードは複合値を生成します。

  1. FMCustomerEntity エンティティのデザイナーで、[フィールド] ノードを右クリックし、[新しい>文字列のマップされていないフィールド] を選択します。

  2. マップされていないフィールドのプロパティ ウィンドウで、名前プロパティを FullName に設定します。

  3. 計算フィールドかどうか プロパティ いいえ に設定します。 DataEntityView メソッドが空のままであることを確認します。

    マップされていないフィールドのプロパティの設定のスクリーンショット。

  4. FMCustomerEntity デザイナーで、[メソッド] ノードを右クリックし、[オーバーライド] > postLoad を選択します。 このメソッドの X++ コードでは、仮想フィールドの値が生成されます。

  5. 次の X++ コードを postLoad オーバーライドに貼り付けます。 postLoad メソッドが void を返すことに注意します。

    public void postLoad()
    {
        super();
        //Populate virtual field once entity has been loaded from database
        //Format full name - "Doe, John"
        this.FullName = this.LastName + ", " + this.FirstName;
    }
    
  6. プロジェクトをコンパイルします。

例: 受信フィールドを受信および解析する仮想フィールドを使用

外部システムが、システムに入ってくる 1 つのフィールドの姓と名を組み合わせた複合値として人物の名前を送信するとします。 ただし、システムは姓と名を別々に格納します。 このシナリオでは、作成した FullName 仮想フィールド使用することができます。 この例で、主要な追加は mapEntityToDataSource メソッドのオーバーライドです。 update を呼び出すと、各データ ソースに対して mapEntityToDataSource メソッドが呼び出されます。

  1. FMCustomerEntity のデザイナーで、[メソッド] ノードを右クリックし、[override > mapEntityToDataSource] を選択します。

  2. 次の X++ コードを mapEntityToDataSource メソッドに貼り付けます。

    public void mapEntityToDataSource(DataEntityRuntimeContext entityCtx, DataEntityDataSourceRuntimeContext dataSourceCtx)
    {
        super(entityCtx, dataSourceCtx);
        //Check if desired data source context is available
        if (dataSourceCtx.name() == "FMCustomer")
        {
            FMCustomer dsCustomer = dataSourceCtx.getBuffer();
            //Find position of "," to parse full name format "Doe, John"
            int commaPosition = strfind(this.FullName, ",",0,strlen(this.FullName));
            //Update FirstName and LastName in the data source buffer to update
            dsCustomer.LastName = substr(this.FullName,0,commaPosition-1);
            dsCustomer.FirstName = substr(this.FullName, commaPosition+1, strlen(this.FullName));
        }
    }
    

計算フィールドと仮想フィールドのテスト

次の main メソッドは、計算フィールドと仮想フィールドをテストします。 読み取りアクションの両方のフィールドをテストし、更新アクションの仮想フィールドをテストします。

  1. この例では、 Fleet Management (移行済み) という名前のデータ セットがあることを確認します。 このデータ セットは、ブラウザーのダッシュボードから見つけることができます。 右上隅にあるメニュー アイコンを選択し、[ アプリ リンク ] メニューを選択し、スクロールして Fleet Management (移行済み) という名前のデータ セットを見つけます。

  2. 次の X++ コードをプロジェクトのスタートアップ オブジェクトに貼り付けます。 プロジェクトを実行します。

    public static void main(Args _args)   // X++
    {
        FMCustomerEntity customer;
        //Using transactions to avoid committing updates to database
        ttsbegin;
        //SELECT single customer entity record from the database
        select customer
            where customer.Email == "phil.spencer@adatum.com";
        //Read full name (Virtual Field)
        info(customer.FullName);
        //Read formatted NameAndAddress(computed Field)
        info(customer.NameAndAddress);
        //UPDATE full name (virtual field)
        customer.FullName = "Doe, John";
        customer.update();
        //Reselect data from database to get updated information
        select customer
            where customer.Email == "phil.spencer@adatum.com";
        //Read full name (virtual field)
        info(customer.FullName);
        ttsabort;
    }
    

計算列の生成に失敗した場合の注意事項

計算列の SQL を生成する X++ メソッドが例外をスローした場合、DbSync は例外をキャッチし、その列の値を NULLに設定し、 警告をログに記録します。

NULL値に達しないようにするには、計算列メソッドで構成キーを手動で確認します。