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 会返回合并的记录,并且不会修改它的参数或任何数据源中的记录。

语法

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

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

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

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

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

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

合并记录

Patch( Record1, Record2 [, …] )

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

示例

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

在以下示例中,您会在名为 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: "Strawberry" } ) IceCream 数据源中创建一条记录。
  • ID 列包含的值为 3,这是数据源自动生成的。
  • Quantity 列的值为 0,在 IceCream 数据源中,这是该列的默认值,由 Defaults 函数指定。
  • Flavor 列的值为 Strawberry
{ ID: 3, Flavor: "Strawberry", Quantity: 0 }

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

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

操作后的 icecream 示例。

合并记录(数据源外部)

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

使用 AsThisRecord

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

在下面的示例中,请考虑 If 语句中的第一个查找。 (OrderID = A[@OrderID]) 应将查找范围中的 OrderIdForAll 范围中集合 AOrderId 进行比较。 在此情况下,您可能希望 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 来消除左侧的歧义。 对于上述情形,建议采用 As

当您的公式在同一个数据源或表上对 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 的用法,请参阅运算符文章。