Patch 函数

适用于: 画布应用 模型驱动应用 Power Platform CLI 桌面流

数据源中修改或创建一条或多条记录,或者合并数据源外的记录。

使用 Patch 函数可以在复杂情况(如执行不需要用户交互的更新或使用跨多个屏幕的窗体)下修改记录。

要更轻松地更新数据源中的记录以进行简单更改,请改用 Edit form 控件。 添加 Edit form 控件时,可以向用户提供要填写的窗体,然后将更改保存到数据源中。 有关详细信息,请参阅了解数据窗体

观看此视频,了解如何使用 Patch 函数:

概述

使用 Patch 函数可修改数据源的一条或多条记录。 可以在不影响其他属性的情况下修改特定字段的值。 例如,以下公式更改名为 Contoso 的客户的电话号码:

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

结合使用 PatchDefaults 函数可创建记录。 可以利用此行为生成一个屏幕,以供创建和编辑记录。 例如,以下公式为名为 Contoso 的客户创建记录:

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

即使不需要使用数据源,也可以使用 Patch 来合并两条或多条记录。 例如,以下公式将两个记录合并成一个同时识别 Contoso 的电话号码和位置的记录:

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

描述

在数据源中修改或创建记录

要在数据源中使用这个函数,请指定数据源,然后指定一条基本记录:

  • 要修改记录,基本记录必须来自数据源。 基本记录可能来自一个库的 Items 属性(在上下文变量中),也可能来自其他途径。 不过,您可以追溯到基本记录来自数据源。 这一点非常重要,因为记录中包含一些额外的信息,可以帮助您重新找到记录,以便进行修改。
  • 要创建记录,请使用 Defaults 函数创建一条包含默认值的基本记录。

然后指定一条或多条更改记录,每条记录都包含用于替代基本记录中属性值的新属性值。 更改记录按照参数列表从头到尾的顺序进行处理,并且使用后者的属性值替换前者的属性值。

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'

更新数据源时,可能会产生一个或多个问题。 将 IfErrorIsErrorPatch 中的返回值配合使用,以检测和响应错误,如错误处理所述。 您还可以使用 Errors 函数识别和检查问题,如使用数据源所述。

相关函数包括 Update 函数来替换整个记录,以及 Collect 函数来创建记录。 使用 UpdateIf 函数可以根据条件来修改多条记录的特定属性。

在数据源中修改或创建一组记录

Patch 还可用于通过一次调用创建或修改多个记录。

它不是传递单条基本记录,而是在第二个参数中提供一个基本记录表。 更改记录也是通过表提供,并且与基本记录一一对应。 每个更改表中记录的数量必须与基本表中记录的数量完全相等。

如果以这种方式使用 Patch 函数,结果值也会是一个表,并且其中的记录与基本记录和更改记录也是一一对应的。

合并数据源外部的记录

指定一条或多条要合并的记录。 记录按照参数列表从头到尾的顺序进行处理,并且使用后者的属性值替换前者的属性值。

Patch 返回合并的记录,并且不会修改其参数或任何数据源中的记录。

语法

在数据源中修改或创建记录

补丁(DataSource,BaseRecord,ChangeRecord1 [, ChangeRecord2 ,... ])

  • DataSource –必需。 包含要修改的记录或用于包含要创建的记录的数据源。
  • BaseRecord –必需。 要修改或创建的记录。 如果记录来自数据源,则会找到记录并进行修改。 如果使用 Defaults 函数的结果,则会创建记录。
  • ChangeRecords –必需。 一条或多条记录,其中包含要在 BaseRecord 中修改的属性。 更改记录按照参数列表从头到尾的顺序进行处理,并且使用后者的属性值替换前者的属性值。

在数据源中修改或创建一组记录

补丁(DataSource,BaseRecordsTable,ChangeRecordTable1 [, ChangeRecordTable2 ,... ])

  • DataSource –必需。 包含要修改的记录或用于包含要创建的记录的数据源。
  • BaseRecordTable –必需。 要修改或创建的记录的表。 如果记录来自数据源,则会找到记录并进行修改。 如果使用 Defaults 函数的结果,则会创建记录。
  • ChangeRecordTables –必需。 记录的一个或多个表,其中包含在 BaseRecordTable 中要修改的每条记录的属性。 更改记录按照参数列表从头到尾的顺序进行处理,并且使用后者的属性值替换前者的属性值。

合并记录

补丁记录 1记录 2 [,...])

  • 记录 - 必需。 至少要有两条要合并的记录。 记录按照参数列表从头到尾的顺序进行处理,并且使用后者的属性值替换前者的属性值。

示例

修改或创建记录(在数据源中)

在以下示例中,您会在名为 IceCream 的数据源中修改或创建一条记录,该数据源包含此中的数据,并且会在 ID 中自动生成相应的值:

icecream 示例。

公式 说明 结果
Patch( IceCream,
LookUp( IceCream, Flavor = "Chocolate" ), { Quantity: 400 } )
修改 IceCream 数据源中的记录:
  • 要修改的记录的 ID 列的值为 1。 (该 ID 的记录为 Chocolate。)
  • Quantity 列的值更改为 400
{ ID: 1, Flavor: "Chocolate", Quantity: 400 }

已修改 IceCream 数据源中的 Chocolate 条目。
patch(IceCream,defaults(IceCream), { flavor:“草莓”) } IceCream 数据源中创建一条记录。
  • ID 列包含的值为 3,这是数据源自动生成的。
  • Quantity 列的值为 0,在 IceCream 数据源中,这是该列的默认值,由 Defaults 函数指定。
  • Flavor 列的值为 Strawberry
{ ID: 3, Flavor: "Strawberry", Quantity: 0 }

已在 IceCream 数据源中创建 Strawberry 条目。

对上面的公式进行计算后,数据源最终会产生以下值:

操作后的 icecream 示例。

合并记录(数据源外部)

公式 描述 结果
补丁( { 名称:“James”,分数:90 }, { 名称:“Jim”,传递:true } ) 合并数据源外的两条记录:
  • 两条记录的 Name 列中的值不相同。 结果包含离参数列表的末尾更近的记录中的值 (Jim),而不是离开头更近的记录中的值 (James)。
  • 第一条记录包含第二条记录中不存在的一列 (Score)。 结果包含这一列及其值 (90)。
  • 第二条记录包含第一条记录中不存在的一列 (Passed)。 结果包含这一列及其值 (true)。
{ Name: "Jim", Score: 90, Passed: true }

使用 AsThisRecord

在公式中使用 AsThisRecord 关键字可避免不明确的计算上下文。

在下面的示例中,请考虑 If 语句中的第一个查找。 (OrderID = A[@OrderID]) 应将 OrderId the in the lookup scope 与 OrderId the A collection in the scope 进行比较 ForAll 。 在此情况下,您可能希望 A[@OrderId] 解析为本地参数。 但这并不明确。

Power Apps 目前将左侧 OrderId 和右侧 A[@OrderId] 都解释为查找范围中的字段。 因此,查找时总是会在 [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"
       }
   )
    )
)

使用 AsThisRecord

只要有可能,请使用 As 运算符或 ThisRecord 来消除左侧的歧义。 对于 上述场景,建议这样做。

当您的公式在同一个数据源或表上对 ForAllFilterLookup 使用多个范围时,范围参数可能会与其他地方的相同字段发生冲突。 因此,建议使用 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 的用法,请参阅运算符文章。