Patch 関数

適用対象: キャンバス アプリ Copilot Studio デスクトップ フロー モデル駆動型アプリ Power Platform CLI Dataverse 関数

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

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

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

Patch関数の使用方法については、次のビデオをご覧ください。

Overview

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

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

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

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

Note

デフォルト値を持ったデータソースのレコードを使ってコレクションをパッチすると、パッチ操作は指定されたパッチ値とデータソースのデフォルト値の両方でコレクションを更新します。 パッチ文のDataSourceとDefaults関数のDataSourceが一致して新しいレコードを作成する必要があります。

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

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

Description

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

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

  • レコードを修正するには、ベースレコードがデータソースから取得する必要があります。 ギャラリーの 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 つ以上の問題が発生する可能性があります。 エラー処理で説明されているように、エラーを検出して対応するには、からの戻り値と共に IfError と Patch を使用します。 データ ソースの利用に関する記事で説明されているとおり、問題の特定と調査には Errors 関数を使用することもできます。

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

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

また、 Patch を使えば、1回の通話で複数のレコードを作成・変更することも可能です。

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

このように Patch を使うと、返還値は各レコードがベースレコードと変更レコードと1対1に対応するテーブルにもなります。

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

マージする 2 つ以上のレコードを指定します。 この関数は、引数リストの最初から終わりまでの順にレコードを処理し、後のプロパティ値は前の値を上書きします。

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

Syntax

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

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

  • DataSource – 必須。 変更するレコードを含むデータ ソースまたはこれから作成するレコードを含むデータ ソース。
  • BaseRecord – 必須。 変更または作成するレコード。 もしレコードがデータソースから来た場合、関数はレコードを見つけて修正します。 Defaultsの結果が使われた場合、関数はレコードを作成します。 新しいレコードを作成するには、patch ステートメントのデータソースと Defaults 関数のデータソースが一致している必要があります。
  • ChangeRecords – 必須。 BaseRecord 内で変更するプロパティを含む、1 つ以上のレコード。 この関数は、引数リストの最初から終わりまでに変更レコードを処理し、後のプロパティ値が前の値に上書きされます。

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

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

  • DataSource – 必須。 変更するレコードを含むデータ ソースまたはこれから作成するレコードを含むデータ ソース。
  • BaseRecordTable – 必須。 変更または作成するレコードのテーブル。 もしレコードがデータソースから来た場合、関数はレコードを見つけて修正します。 Defaultsの結果が使われた場合、関数はレコードを作成します。 新しいレコードを作成するには、patch ステートメントのデータソースと Defaults 関数のデータソースが一致している必要があります。
  • ChangeRecordTables – 必須。 BaseRecordTable の各レコードで変更するプロパティを含む、1 つ以上のレコード テーブル。 この関数は、引数リストの最初から終わりまでに変更レコードを処理し、後のプロパティ値が前の値に上書きされます。

Merge records

Patch( Record1, Record2 [, ...] )

  • 記録 - 必須。 少なくとも 2 つ以上の、マージするレコード。 関数は、引数リストの最初から終わりまで順にレコードを処理し、後のプロパティ値は前の値を上書きします。

Examples

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

これらの例では、 IceCreamという名前のデータソースでレコードを修正または作成します。 データソースはこの テーブル のデータを持ち、 ID列の値を自動生成します:

IceCreamのデータソースのサンプルテーブルのスクリーンショットで、フレーバーと量を示しています。

このデータソースのメモリ版を作成し、これらの例を試すために、次の式を評価してください:

ClearCollect( IceCream,
    { ID: 1, Flavor: "Chocolate", Quantity: 100 },
    { ID: 2, Flavor: "Vanilla", Quantity: 200 }
)
Formula Description Result
Patch( IceCream、
LookUp(アイスクリーム、フレーバー=「チョコレート」)、{ 数量:400 } )
IceCream データ ソース内のレコードを変更します。
  • 変更するレコードの ID 列には、値 1 が含まれます。 (Chocolate レコードの ID がこれです。)
  • Quantity 列の値が 400 に変更されます。
{ ID: 1, フレーバー:「チョコレート」, 数量: 400 }

IceCreamのデータソースにおけるチョコレートのエントリが修正されています。
Patch(アイスクリーム、デフォルト(アイスクリーム)、{ フレーバー:「ストロベリー」}) IceCream データ ソース内のレコードを作成します。
  • ID 列には値 3 が含まれます。これはデータ ソースが自動的に生成するものです。
  • Quantity 列には 0 が含まれます。これは Defaults 関数で指定するとおり、IceCream データ ソースにおけるこの列の既定値です。
  • Flavor 列には Strawberry という値が含まれます。
{ ID: 3, フレーバー: "ストロベリー", 数量: 0 }

IceCreamのデータソースにストロベリーのエントリが作成されます。

前の式を評価した後、データソースは以下の値で終わります。

Patch式評価後のアイスクリームデータソースのスクリーンショットです。

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

Formula Description Result
Patch({ 名前:「ジェームズ」、スコア:90 }、{ 名前:「ジム」、合格:真 } ) データ ソースの外部で 2 つのレコードをマージします。
  • 各レコードの Name 列の値は一致しません。 結果には、引数リストの先頭に近いレコードの値 (James) ではなく、末尾に近いレコードの値 (Jim) が含まれます。
  • 最初のレコードには、2 番目のレコードには存在しない列 (Score) が含まれます。 結果には、その列とその値 (90) が含まれます。
  • 2 番目のレコードには、最初のレコードには存在しない列 (Passed) が含まれます。 結果には、その列とその値 (true) が含まれます。
{ 名前:「ジム」、スコア:90、合格:真 }

レコードのセットを修正または作成する(データソース内で)

単一のレコードではなくテーブルで使う Patch を使うと、1回の呼び出しで複数のレコードを作成・変更できます。 返却値は、入力テーブルと1対1に対応するレコードのテーブルです。

この例は、IceCreamデータソース内の複数のフレーバーのQuantityを同時に更新しています:

Patch(
    IceCream,
    Table(
        { ID: 1, Flavor: "Chocolate", Quantity: 150 },
        { ID: 2, Flavor: "Vanilla", Quantity: 200 }
    ),
    Table(
        { Quantity: 300 },
        { Quantity: 400 }
    )
)

その結果、更新された記録の表ができ { ID: 1, Flavor: "Chocolate", Quantity: 300 } と { ID: 2, Flavor: "Vanilla", Quantity: 400 }が完成します。

この例は Defaultsを使って複数の新しいレコードを作成します:

Patch(
    IceCream,
    Table( Defaults( IceCream ), Defaults( IceCream ) ),
    Table(
        { Flavor: "Mint", Quantity: 60 },
        { Flavor: "Peach", Quantity: 80 }
    )
)

Note

テーブルで Patch を使う場合、各変更テーブルのレコード数はベーステーブルのレコード数と一致しなければなりません。 それ以外の場合、エラーが発生します。

複数のレコードを修正した際にエラーを検出するには 、IfErrorを使います。 IfError は推奨されるメカニズムであり、Power FXホスト全体で動作します:

IfError(
    Patch(
        IceCream,
        baseRecords,
        changeRecords
    ),
    Notify( "Some records failed to update: " & FirstError.Message, NotificationType.Error )
)

Patch Dataverseのカラムタイプで

以下の例は特にMicrosoft Dataverseデータソースに当てはまります。 レコード形状はデータソースによって異なります(例えば、SharePointとSQL Serverは異なるフォーマットを持っています)。

選択欄: Choice列を設定するには、enum値を直接使います。 この例は、アカウントテーブルにステータス選択列を設定します:

Patch(
    Accounts,
    LookUp( Accounts, 'Account Name' = "Contoso" ),
    { 'Status': 'Status (Accounts)'.Active }
)

検索コラム: Lookup列を設定するには、関連するテーブルの主キーを持つレコードを提供します。 この例は、アカウントレコードのプライマリコンタクル検索を設定します:

Patch(
    Accounts,
    LookUp( Accounts, 'Account Name' = "Contoso" ),
    { 'Primary Contact': LookUp( Contacts, 'Full Name' = "John Smith" ) }
)

Note

これらのカラムタイプの例はDataverse固有のものです。 SharePointやSQL Serverなどの他のデータソースでは、類似した列タイプに対して異なるレコード形状が必要になることがあります。 正しいフォーマットについては、特定のデータソースのドキュメントを参照してください。

次の式における委譲 Patch

Patch関数自体はデータソースに書き込みを行うため、委託の対象ではありません。 しかし、 Patch を使う式では、 Filter、 LookUp、 ForAllなどのレコード選択部分がデータソースの委任制限を超えるクエリを含む場合、委任警告が現れることがあります。

Patchを含む数式に委任警告が表示された場合は、その警告がデータ検索機能自体に適用されるのか、それともデータ検索機能自体に適用されるのかPatch確認してください。 委任についての詳細は 、「Understanding delegation in a Canvas app(キャンバスアプリにおける委任の理解)」をご覧ください。

Patch関数の一般的な誤り

Patch関数を使用すると、データソースの接続性、権限、またはデータ競合のためにエラーが発生することがあります。 IfErrorとIsErrorを使ってエラーを検出し、適切に応答してください。

  • 「 Patch 関数使用時のネットワークエラー」:このエラーは通常、アプリがデータソースにアクセスできないことを示します。 一般的な原因には、インターネット接続の喪失、データソースの一時的な利用不可、または現在のユーザーの権限不足などがあります。 Patch呼び出しをIfErrorでラップして、ユーザーに意味のあるメッセージを伝えます。

  • 「サーバー上の変更と競合が存在する」:このエラーは、アプリがレコードを読み書きする間に別のユーザーやプロセスが同じレコードを変更した場合に発生します。 リ フレッシュ 関数を呼び出してデータソースをリフレッシュし、操作をやり直します。

  • 権限エラー:ユーザーがデータソース内でレコードを作成または変更する権限を持っていない場合、 Patch 呼び出しは失敗します。 IfErrorを使って権限関連のエラーを検出し、ユーザーを導きます。

一般的なエラー処理パターンについては 、エラー処理を参照してください。

As または ThisRecord の使用

評価の曖昧な文脈を避けるために、公式に 「As 」または 「ThisRecord 」キーワードを用いましょう。

次の例では、If文の最初のLookupを考えます。 (OrderID = A[@OrderID]) Lookupの範囲内のOrderIdとForAllの範囲における収集AのOrderIdを比較することが期待されています。 この場合、 A[@OrderId] を局所パラメータとして解決したいのでしょう。 しかし、それは曖昧です。

Power Apps現在、左側OrderIdおよび右側A[@OrderId]の両方をLookupの範囲内の場として解釈しています。 したがって、条件が常に真であるため、 Lookup は [dbo].[Orders1] の最初の行を見つける(すなわち、任意の行の OrderId は自分自身と等しい)。

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 キーワードを使用してください。 前述のシナリオでも推奨されています。

同じデータソースやテーブル上で ForAll、 Filter、 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の使用について詳しく知りたい方は、Operatorsの記事をご覧ください。