适用于: 画布应用
Copilot Studio
Desktop 流
模型驱动应用
Power Platform CLI
Dataverse 函数
在数据源中修改或创建一条或多条记录,或者合并数据源外的记录。
使用 Patch 函数修改复杂情况下的记录,例如,执行不需要用户交互的更新或使用跨多个屏幕的表单时。
要更轻松地更新数据源中的记录以进行简单更改,请改用 Edit form 控件。 添加 Edit form 控件时,可以向用户提供要填写的窗体,然后将更改保存到数据源中。 有关详细信息,请参阅了解数据窗体。
观看此视频,了解如何使用函数 Patch :
Overview
使用该 Patch 函数修改数据源的一个或多个记录。 它更新特定 字段 的值而不影响其他属性。 例如,以下公式更改名为 Contoso 的客户的电话号码:
Patch( Customers, LookUp( Customers, Name = "Contoso" ), { Phone: "1-212-555-1234" } )
与 PatchDefaults 函数一起使用以创建记录。 可以利用此行为生成一个屏幕,以供创建和编辑记录。 例如,以下公式为名为 Contoso 的客户创建记录:
Patch( Customers, Defaults( Customers ), { Name: "Contoso" } )
Note
当你用数据源的默认值记录来修补集合时,补丁操作会同时更新集合,同时更新指定的补丁值和数据源的默认值。 补丁语句的数据源与默认函数的数据源必须匹配才能创建新记录。
即使未使用数据源,也可以使用 Patch 合并两条或更多条记录。 例如,以下公式将两个记录合并成一个同时识别 Contoso 的电话号码和位置的记录:
Patch( { Name: "Contoso", Phone: "1-212-555-1234" }, { Name: "Contoso", Location: "Midtown" } )
Description
在数据源中修改或创建记录
要在数据源中使用这个函数,请指定数据源,然后指定一条基本记录:
- 要修改记录,基础记录必须来自数据源。 你可以通过画廊的 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'
更新数据源时,可能会出现一个或多个问题。 将 IfError 和 IsError 与返回值 Patch 一起使用,以检测和响应错误,如 错误处理 所述。 您还可以使用 Errors 函数识别和检查问题,如使用数据源所述。
相关函数包括 Update 函数来替换整个记录,以及 Collect 函数来创建记录。 使用 UpdateIf 函数可以根据条件来修改多条记录的特定属性。
在数据源中修改或创建一组记录
你也可以用 Patch 一次调用创建或修改多个记录。
不要传递单个基记录,而是在第二个参数中提供基记录的表。 也要在表格中提供变更记录,与基础记录一一对应。 每个更改表中记录的数量必须与基本表中记录的数量完全相等。
以这种方式使用 Patch 时,返回值也是一个表格,每个记录与基础记录和变更记录一一对应。
合并数据源外部的记录
指定一条或多条要合并的记录。 该函数按参数列表开始到结束的顺序处理记录,后续属性值覆盖较早的值。
Patch 返回合并的记录,并且不会修改其任何数据源中的参数或记录。
Syntax
在数据源中修改或创建记录
Patch( DataSource、 BaseRecord、 ChangeRecord1 [、 ChangeRecord2、... ])
- DataSource – 必需。 包含要修改的记录或用于包含要创建的记录的数据源。
- BaseRecord –必需。 要修改或创建的记录。 如果记录来自数据源,函数会查找并修改该记录。 如果使用了 Defaults 的结果,函数会创建记录。 patch 语句的 DataSource 和 Defaults 函数的 DataSource 必须匹配才能创建新记录。
- ChangeRecords –必需。 一条或多条记录,其中包含要在 BaseRecord 中修改的属性。 该函数按参数列表开头到末尾的顺序处理变更记录,后续属性值覆盖较早的值。
在数据源中修改或创建一组记录
Patch( DataSource、 BaseRecordsTable、 ChangeRecordTable1 [、 ChangeRecordTable2、... ] )
- DataSource – 必需。 包含要修改的记录或用于包含要创建的记录的数据源。
- BaseRecordTable –必需。 要修改或创建的记录的表。 如果记录来自数据源,函数会查找并修改该记录。 如果使用了 Defaults 的结果,函数会创建记录。 patch 语句的 DataSource 和 Defaults 函数的 DataSource 必须匹配才能创建新记录。
- ChangeRecordTables –必需。 记录的一个或多个表,其中包含在 BaseRecordTable 中要修改的每条记录的属性。 该函数按参数列表开头到末尾的顺序处理变更记录,后续属性值覆盖较早的值。
Merge records
Patch(Record1,Record2 [,...] )
- 记录 - 必需。 至少要有两条要合并的记录。 该函数按参数列表开头到结尾的顺序处理记录,后续属性值覆盖较早的值。
Examples
修改或创建记录(在数据源中)
在这些示例中,你修改或创建一个名为 IceCream的数据源记录。 数据源包含该 表 中的数据,并自动生成 ID列中的值:
要创建内存中的该数据源版本以便尝试以下示例,请评估以下公式:
ClearCollect( IceCream,
{ ID: 1, Flavor: "Chocolate", Quantity: 100 },
{ ID: 2, Flavor: "Vanilla", Quantity: 200 }
)
| Formula | Description | Result |
|---|---|---|
|
Patch(IceCream, LookUp(IceCream, Flavor = “Chocolate” ), { Quantity: 400 } ) |
修改 IceCream 数据源中的记录:
|
{ ID: 1, 风格: “Chocolate”, Quantity: 400 } IceCream 数据源中的巧克力条目被修改。 |
| Patch(IceCream, Defaults( IceCream), { Flavor: “草莓” } ) | 在 IceCream 数据源中创建一条记录。
|
{ ID: 3, 风格: “草莓”, 数量: 0 } IceCream 数据源中的 Strawberry 条目被创建。 |
在计算完之前的公式后,数据源以以下数值结束:
合并记录(数据源外部)
| Formula | Description | Result |
|---|---|---|
| Patch( { Name: “James”, Score: 90 }, { Name: “Jim”, Passed: true } ) | 合并数据源外的两条记录:
|
{ Name: “Jim”, Score: 90, Passed: true } |
修改或创建一组记录(在数据源中)
当你用表而不是单条记录时 Patch ,可以在一次调用中创建或修改多个记录。 返回值是一个记录表,与输入表一一对应。
此示例同时更新了IceCream数据源中多种口味的数量:
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 }。
此示例使用 默认值创建多个新记录:
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列,直接使用枚举值。 此示例在账户表上设置状态选择列:
Patch(
Accounts,
LookUp( Accounts, 'Account Name' = "Contoso" ),
{ 'Status': 'Status (Accounts)'.Active }
)
查找专栏: 要设置查找列,请提供带有相关表主键的记录。 本例设置了账户记录的主要联系人查询:
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 针对自身。 有关委托的更多信息,请参见 “理解 canvas 应用中的委托”。
函数的 Patch 常见错误
使用该 Patch 函数时,可能因数据源连接、权限或数据冲突而出错。 使用 IfError 和 IsError 来检测错误并做出相应响应。
“使用 Patch 函数时出现网络错误”:此错误通常表示应用无法访问数据源。 常见原因包括网络连接中断、数据源暂时不可用,或当前用户权限不足。 用 IfError 封装调用Patch,向用户传递有意义的信息。
“服务器上的更改存在冲突”:当其他用户或进程在你的应用读取记录并写入更改之间修改了同一记录时,就会发生此错误。 通过调用 刷新 函数刷新数据源并重新尝试操作。
权限错误:如果用户没有权限在数据源中创建或修改记录,调用 Patch 将失败。 使用 IfError 来发现与权限相关的错误并引导用户。
有关一般的错误处理模式,请参见 错误处理。
使用 As 或 ThisRecord
在公式中使用 “As ”或 “ThisRecord ”关键字,以避免评估语境中的歧义。
在下一个例子中,考虑陈If述中的第一个Lookup。
(OrderID = A[@OrderID])预计将 在范围内AOrderIdForAll与 在范围内的收集 进行比较。OrderIdLookup 在这种情况下,你可能想 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 关键字来消歧左侧。 正如 前述情景所推荐的那样。
当你的公式使用多个作用域,且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 的使用情况,请参阅 Operators 文章。