Patch 関数

適用対象: Canvas アプリ モデル駆動型アプリ Power Platform CLI

データ ソース 内で 1 つ以上の レコード を変更または作成するか、データ ソースの外部でレコードをマージします。

Patch 関数を使用して、ユーザーの操作を必要としない更新を実行する場合や複数の画面にまたがったフォームを使用するなど、複雑な状況でレコードを変更します。

簡単な変更のためにデータ ソースのレコードを簡単に更新するには、代わりに Edit form コントロールを使用します。 Edit form コントロールを追加する場合には、データ ソースへの変更を入力し、その後保存するためのフォームをユーザーに提供します。 詳細については、データ フォームの概要 を参照してください。

このビデオでは、Patch 機能の使い方について説明します:

概要

Patch 関数を使用して、データ ソースの 1 つ以上のレコードを変更します。 特定の フィールド の値が、その他のプロパティに影響を与えることなく変更されます。 たとえば、次の式では、Contoso という名前の顧客の電話番号が変更されます。

Patch( Customers, First( Filter( Customers, Name = "Contoso" ) ), { Phone: "1-212-555-1234" } )

Patch は、レコードを作成するために Defaults 関数と併せて使用します。 この動作は、レコードの作成と編集に使用する 単一の画面 を構築するのに使用できます。 たとえば、次の式では、Contoso という名前の顧客のレコードが作成されます。

Patch( Customers, Defaults( Customers ), { Name: "Contoso" } )

データ ソースを使用していない場合でも、Patch を使用して 2 つ以上のレコードをマージすることができます。 たとえば、次の式では、2 つのレコードがマージされ、Contoso の電話番号と所在地の両方を識別するレコードが作成されます。

Patch( { Name: "Contoso", Phone: "1-212-555-1234" }, { Name: "Contoso", Location: "Midtown" } )

内容

データ ソースのレコードを変更または作成する

データ ソースに対してこの関数を使用するには、データ ソースを指定し、基本レコードを指定します。

  • レコードを変更する場合、基本レコードはデータ ソースからのものである必要があります。 基本レコードは、ギャラリーの Items プロパティから取得されて コンテキスト変数 内に配置されることも、他のパスを通じて取得されることもあります。 しかし、基本レコードはデータ ソースまで追跡することができます。 レコードには、変更する際にそのレコードを再度特定するのに役立つ情報を追加するため、これは重要です。
  • レコードを作成する際は、Defaults 関数を使用して既定値で基本レコードを作成します。

次に、1 つ以上の変更レコードを指定します。各レコードには、基本レコード内のプロパティ値をオーバーライドする新しいプロパティ値が含まれます。 変更レコードは、引数リストの先頭から末尾まで順に処理されます。その際、前のプロパティ値は後のプロパティ値によって上書きされます。

Patch の戻り値は、変更または作成したレコードです。 レコードを作成した場合、戻り値にはデータ ソースによって自動的に生成されたプロパティが含まれる場合があります。 ただし、戻り値は、関連するテーブルのフィールドの値を提供しません。

たとえば、Set(MyAccount, Patch(Accounts, First(Account), 'Account Name': "Example name")); を使用し、その後 MyAccount.'Primary Contact'.'Full Name' を使用します。 この場合、フル ネームを取得することはできません。 代わりに、関連するテーブルのフィールドにアクセスするには、次のような別のルックアップを使用します。

LookUp(Accounts, Account = MyAccount.Account).'Primary Contact'.'Full Name'

データ ソースを更新するとき、1 つまたは複数の問題が発生する場合があります。 エラー処理で説明されているように、IfErrorIsErrorPatch からの戻り値と共に使用して、エラーを検出し、対応します。 データ ソースの利用に関する記事で説明されているとおり、問題の特定と調査には Errors 関数を使用することもできます。

関連する関数に、レコード全体を置き換える Update 関数および、レコードを作成する Collect 関数が含まれます。 UpdateIf 関数を使用し、条件に基づいて複数のレコードの特定のプロパティを変更できます。

データ ソースのレコード セットを変更または作成する

Patch は、1 回の呼び出しで複数のレコードを作成または変更するときにも使用できます。

基本レコードを 1 つ渡す代わりに、2 番目の引数で基本レコードのテーブルを渡せます。 変更レコードもテーブルで渡され、基本レコードに一対一で対応します。 各変更テーブル内のレコードの数は、基本テーブル内のレコードの数と同じである必要があります。

この方法で Patch を使用した場合、戻り値もテーブルになり、その各レコードは基本レコードと変更レコードに一対一で対応します。

データ ソースの外部でレコードをマージする

マージする 2 つ以上のレコードを指定します。 レコードは、引数リストの先頭から末尾まで順に処理されます。その際、前のプロパティ値は後のプロパティ値によって上書きされます。

Patch はマージされたレコードを返します。引数またはデータ ソース内のレコードは変更されません。

構文

データ ソースのレコードを変更または作成する

Patch( DataSource, BaseRecord, ChangeRecord1 [, ChangeRecord2, … ])

  • DataSource – 必須。 変更するレコードを含むデータ ソースまたはこれから作成するレコードを含むデータ ソース。
  • BaseRecord – 必須。 変更または作成するレコード。 レコードがデータ ソースからのものだった場合、レコードが検出され、変更されます。 Defaults の結果を使用した場合、レコードが作成されます。
  • ChangeRecord(s) – 必須。 BaseRecord 内で変更するプロパティを含む、1 つ以上のレコード。 変更レコードは、引数リストの先頭から末尾まで順に処理されます。その際、前のプロパティ値は後のプロパティ値によって上書きされます。

データ ソースのレコード セットを変更または作成する

Patch( DataSource, BaseRecordsTable, ChangeRecordTable1 [, ChangeRecordTable2, … ] )

  • DataSource – 必須。 変更するレコードを含むデータ ソースまたはこれから作成するレコードを含むデータ ソース。
  • BaseRecordTable – 必須。 変更または作成するレコードのテーブル。 レコードがデータ ソースからのものだった場合、レコードが検出され、変更されます。 Defaults の結果を使用した場合、レコードが作成されます。
  • ChangeRecordTable(s) – 必須。 BaseRecordTable の各レコードで変更するプロパティを含む、1 つ以上のレコード テーブル。 変更レコードは、引数リストの先頭から末尾まで順に処理されます。その際、前のプロパティ値は後のプロパティ値によって上書きされます。

レコードの統合

Patch( Record1, Record2 [, …] )

  • Record(s) - 必須。 少なくとも 2 つ以上の、マージするレコード。 レコードは、引数リストの先頭から末尾まで順に処理されます。その際、以前のプロパティ値は後のプロパティ値によって上書きされます。

(データ ソース 内の) レコードを変更または作成する

これらの例では、IceCream というデータ ソースのレコードを変更または作成します。このデータ ソースは次の テーブル のデータを含み、ID内 の値を自動的に生成します。

例 Icecream。

Description Result
Patch( IceCream,
LookUp( IceCream, Flavor = "Chocolate" ), { Quantity: 400 } )
IceCream データ ソース内のレコードを変更します。
  • 変更するレコードの ID 列には、値 1 が含まれます。 (Chocolate レコードの ID がこれです。)
  • Quantity 列の値が 400 に変更されます。
{ ID: 1, Flavor: "Chocolate", Quantity: 400 }

IceCream データ ソースの Chocolate エントリが変更されています。
Patch( IceCream, Defaults( IceCream ), { Flavor: "Strawberry" } ) IceCream データ ソース内のレコードを作成します。
  • ID 列には値 3 が含まれます。これはデータ ソースが自動的に生成するものです。
  • Quantity 列には 0 が含まれます。これは Defaults 関数で指定するとおり、IceCream データ ソースにおけるこの列の既定値です。
  • Flavor 列には Strawberry という値が含まれます。
{ ID: 3, Flavor: "Strawberry", Quantity: 0 }

IceCream データ ソースの Strawberry エントリが作成されています。

前の数式が評価された後、データ ソースはこれらの値で終了します。

後の icecream の例

(データ ソースの外部で) レコードをマージする

内容 結果
Patch( { Name: "James", Score: 90 }, { Name: "Jim", Passed: true } ) データ ソースの外部で 2 つのレコードをマージします。
  • 各レコードの Name 列の値は一致しません。 結果には、引数リストの先頭に近いレコードの値 (James) ではなく、末尾に近いレコードの値 (Jim) が含まれます。
  • 最初のレコードには、2 番目のレコードには存在しない列 (Score) が含まれます。 結果には、その列とその値 (90) が含まれます。
  • 2 番目のレコードには、最初のレコードには存在しない列 (Passed) が含まれます。 結果には、その列とその値 (true) が含まれます。
{ Name: "Jim", Score: 90, Passed: true }

As または ThisRecord の使用

式で As または ThisRecord キーワードを使用すると、あいまいな評価コンテキストを回避します。

以下の例では、If ステートメントの最初のルックアップについて考えてみます。 (OrderID = A[@OrderID]) はルックアップ スコープの OrderIdForAll スコープのコレクション AOrderId と比較する必要があります。 この場合、A[@OrderId] をローカル パラメータとして解決する必要があります。 しかし、それはあいまいです。

Power Apps は現在、左側の OrderId と右側の A[@OrderId] の両方をルックアップ スコープのフィールドとして解釈します。 したがって、条件が常に真 (つまり、どの行の OrderId もそれ自体に等しい) であるため、ルックアップでは常に [dbo].[Orders1] の最初の行が検索されます。

ClearCollect(
    A,
    Filter(
        '[dbo].[Orders1]',
        OrderId = 8888888
    )
);
ForAll(
    A,
    If(
        LookUp(
            '[dbo].[Orders1]',
            OrderId = A[@OrderId],
            "OK"
        ) = "OK",
        Patch(
            '[dbo].[Orders1]',
            LookUp(
                '[dbo].[Orders1]',
                OrderId = A[@OrderId]
            ),
            {
      OrderName: "val1"
       }
   ),
   Patch(
            '[dbo].[Orders1]',
            Defaults('[dbo].[Orders1]'),
            {
      OrderName: "val2"
       }
   )
    )
)

As または ThisRecord の使用

可能な限り、As 演算子または ThisRecord を使用して、左側を明確にします。 上記のシナリオでは、As をお勧めします。

式で同じデータ ソースまたはテーブルの ForAllFilter、および Lookup で複数のスコープを使用する場合、スコープ パラメーターが他の場所の同じフィールドと衝突する可能性があります。 したがって、As 演算子または ThisRecord を使用して、フィールド名を解決し、あいまいさを回避することをお勧めします。

たとえば、以下の例では As 演算子を使用して曖昧さを解消することができます。

ClearCollect(
    A,
    Filter(
        '[dbo].[Orders1]',
        OrderId = 8888888
    )
);
ForAll(
    A,
    If(
        LookUp(
            '[dbo].[Orders1]' As B,
            B.OrderId = A[@OrderId],
            "OK"
        ) = "OK",
        Patch(
            '[dbo].[Orders1]',
            LookUp(
                '[dbo].[Orders1]' As C,
                C.OrderId = A[@OrderId]
            ),
            {
      OrderName: "val1"
       }
   ),
   Patch(
            '[dbo].[Orders1]',
            Defaults('[dbo].[Orders1]'),
            {
      OrderName: "val2"
       }
   )
    )
)

または、ThisRecord を同じ目的で使用できます。

ClearCollect(
    A,
    Filter(
        '[dbo].[Orders1]',
        OrderId = 8888888
    )
);
ForAll(
    A,
    If(
        LookUp(
            '[dbo].[Orders1]',
            ThisRecord.OrderId = A[@OrderId],
            "OK"
        ) = "OK",
        Patch(
            '[dbo].[Orders1]',
            LookUp(
                '[dbo].[Orders1]',
                ThisRecord.OrderId = A[@OrderId]
            ),
            {
      OrderName: "val1"
       }
   ),
   Patch(
            '[dbo].[Orders1]',
            Defaults('[dbo].[Orders1]'),
            {
      OrderName: "val2"
       }
   )
    )
)

As 演算子と ThisRecord の使用法の詳細については、演算子 の記事を参照してください。