Skip to content

Commit 8a201cb

Browse files
Live publish for 10 February 2024.
2 parents 0ca06f6 + 7814101 commit 8a201cb

File tree

6 files changed

+193
-155
lines changed

6 files changed

+193
-155
lines changed

.openpublishing.redirection.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
{
22
"redirections": [
3+
{
4+
"source_path": "powerapps-docs/developer/data-platform/upsertmultiple.md",
5+
"redirect_url": "bulk-operations#upsertmultiple",
6+
"redirect_document_id": "false"
7+
},
38
{
49
"source_path": "powerapps-docs/developer/data-platform/org-service/extend-code-generation-tool.md",
510
"redirect_url": "/dynamics365/customerengagement/on-premises/developer/org-service/extend-code-generation-tool",

powerapps-docs/developer/data-platform/TOC.yml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,6 @@
4949
- name: Bulk Operation messages
5050
href: bulk-operations.md
5151
items:
52-
- name: Use UpsertMultiple (preview)
53-
href: upsertmultiple.md
5452
- name: Use DeleteMultiple (preview)
5553
href: deletemultiple.md
5654
- name: Create your own messages

powerapps-docs/developer/data-platform/best-practices/business-logic/avoid-batch-requests-plugin.md

Lines changed: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,15 @@
11
---
2-
title: "Do not use batch request types in plug-ins and workflow activities | MicrosoftDocs"
2+
title: "Don't use batch request types in plug-ins and workflow activities | MicrosoftDocs"
33
description: "You shouldn't use ExecuteMultipleRequest or ExecuteTransactionRequest message request classes within the context of a plug-in or workflow activity."
4-
services: ''
54
suite: powerapps
6-
documentationcenter: na
75
author: jowells
8-
editor: ''
9-
tags: ''
10-
11-
ms.devlang: na
12-
ms.topic: article
13-
ms.tgt_pltfrm: na
14-
ms.workload: na
15-
ms.date: 12/06/2019
6+
ms.date: 02/08/2024
167
ms.subservice: dataverse-developer
178
ms.author: jowells
189
search.audienceType:
1910
- developer
2011
---
21-
# Do not use batch request types in plug-ins and workflow activities
22-
23-
12+
# Don't use batch request types in plug-ins and workflow activities
2413

2514
**Category**: Usage, Reliability, Performance
2615

@@ -30,28 +19,38 @@ search.audienceType:
3019

3120
## Symptoms
3221

33-
Due to their long-running nature, using <xref:Microsoft.Xrm.Sdk.Messages.ExecuteMultipleRequest> or <xref:Microsoft.Xrm.Sdk.Messages.ExecuteTransactionRequest> message request classes within the context of a plug-in or workflow activity expose sandbox-isolated plug-in types to the two-minute (120000ms) channel timeout exception and can degrade the user experience for synchronous registrations.
22+
User experiences are degraded and time out errors might occur when you use *batch request types* in plug-ins and workflow activities that occur within synchronous operations.
23+
24+
The following message request classes are considered *batch request types* because they perform operations on multiple records within a single request:
25+
26+
- <xref:Microsoft.Xrm.Sdk.Messages.ExecuteMultipleRequest>
27+
- <xref:Microsoft.Xrm.Sdk.Messages.ExecuteTransactionRequest>
28+
- <xref:Microsoft.Xrm.Sdk.Messages.CreateMultipleRequest>
29+
- <xref:Microsoft.Xrm.Sdk.Messages.UpdateMultipleRequest>
30+
- <xref:Microsoft.Xrm.Sdk.Messages.UpsertMultipleRequest>
3431

3532

3633
<a name='guidance'></a>
3734

3835
## Guidance
3936

40-
Use these batch messages where code is being executed outside of the platform execution pipeline, such as integration scenarios where network latency would likely reduce the throughput and increase the duration of larger, bulk operations.
37+
Use these batch messages in client applications to perform operations on multiple records. Don't use these messages within code that Dataverse invokes during the execution of another operation: a plug-in or workflow activity registered for a synchronous step.
4138

4239
More specifically, use them in the following scenarios:
4340

4441
- Use <xref:Microsoft.Xrm.Sdk.Messages.ExecuteMultipleRequest> to bulk load data or external processes that are intentional about executing long-running operations (greater than two minutes).
4542

46-
- Use <xref:Microsoft.Xrm.Sdk.Messages.ExecuteMultipleRequest> to minimize the round trips between custom client and Dynamics 365 servers, thereby reducing the cumulative latency incurred.
43+
- Use <xref:Microsoft.Xrm.Sdk.Messages.ExecuteMultipleRequest> to minimize the round trips between custom client and Dataverse servers, to reduce the cumulative latency incurred.
44+
45+
- Use <xref:Microsoft.Xrm.Sdk.Messages.ExecuteTransactionRequest> for external clients that require the batch of operations to be committed as a single, atomic database transaction or rollback if any exception is encountered. Be aware of the potential for database blocking during the long-running transaction.
4746

48-
- Use <xref:Microsoft.Xrm.Sdk.Messages.ExecuteTransactionRequest> for external clients that require the batch of operations to be committed as a single, atomic database transaction or rollback if any exception is encountered. Be aware of the potential for database blocking for the duration of the long-running transaction.
47+
- [Use bulk operation messages](../../bulk-operations.md) (<xref:Microsoft.Xrm.Sdk.Messages.CreateMultipleRequest>, <xref:Microsoft.Xrm.Sdk.Messages.UpdateMultipleRequest>, and <xref:Microsoft.Xrm.Sdk.Messages.UpsertMultipleRequest>) for the same scenarios and to achieve a higher level of throughput.
4948

5049
<a name='problem'></a>
5150

5251
## Problematic patterns
5352

54-
Below is an example usage of <xref:Microsoft.Xrm.Sdk.Messages.ExecuteMultipleRequest> in the context of a plug-in.
53+
The following example shows using <xref:Microsoft.Xrm.Sdk.Messages.ExecuteMultipleRequest> in the context of a plug-in.
5554

5655
> [!WARNING]
5756
> This scenario should be avoided.
@@ -100,11 +99,13 @@ This example includes usage of the type directly with the `Execute` method. The
10099

101100
## Additional information
102101

103-
`ExecuteMultiple` and `ExecuteTransaction` messages are considered batch request messages. Their purpose is to minimize round trips between client and server over high-latency connections. Plug-ins either execute directly within the application process or in close proximity when sandbox-isolated, meaning latency is rarely an issue. Plug-in code should be very focused operations that execute quickly and minimize blocking to avoid exceeding timeout thresholds and ensure a responsive system for synchronous scenarios. Simply submit each request directly instead of batching them and submitting as a single request.
102+
The purpose of the `ExecuteMultiple` message is to minimize round trips between client and server over high-latency connections. Plug-ins either execute directly within the application process or in close proximity when sandbox-isolated, meaning latency is rarely an issue. Plug-in code should be focused operations that execute quickly and minimize blocking to avoid exceeding timeout thresholds and ensure a responsive system for synchronous scenarios. Submit each request directly instead of batching them and submitting as a single request.
104103

105104
For example: `foreach (request in requests) service.Execute(request)`
106105

107-
On the server side, the operations included in a batch request are executed sequentially and aren't done in parallel. This is the case even if the <xref:Microsoft.Xrm.Sdk.ExecuteMultipleSettings>.<xref:Microsoft.Xrm.Sdk.ExecuteMultipleSettings.ReturnResponses> property is set to false. Developers tend to use batch requests in this manner assuming that it will allow for parallel processing. Batch requests won't accomplish this objective. Another common motivator is an attempt to ensure that each operation is included in a transaction. This is unnecessary because the plug-in is often already being executed within the context of a database transaction, negating the need to use the `ExecuteTransaction` message.
106+
On the server side, the operations included in a batch request are executed sequentially and aren't done in parallel. This is the case even if the <xref:Microsoft.Xrm.Sdk.ExecuteMultipleSettings>.<xref:Microsoft.Xrm.Sdk.ExecuteMultipleSettings.ReturnResponses> property is set to false. Developers tend to use batch requests in this manner assuming that it allows for parallel processing. Batch requests don't accomplish this objective.
107+
108+
People use <xref:Microsoft.Xrm.Sdk.Messages.ExecuteTransactionRequest> to ensure that each operation is included in a transaction. This is unnecessary within a synchronous plug-in step because the plug-in already being executed within the context of a database transaction, negating the need to use the `ExecuteTransaction` message.
108109

109110
<a name='seealso'></a>
110111

powerapps-docs/developer/data-platform/bulk-operations.md

Lines changed: 160 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
---
22
title: Use bulk operation messages
33
description: Learn how to use special APIs to perform operations on multiple rows of data in a Microsoft Dataverse table.
4-
ms.date: 11/13/2023
4+
ms.date: 02/08/2024
55
author: divkamath
66
ms.author: dikamath
77
ms.reviewer: jdaly
@@ -20,7 +20,7 @@ To get the best performance when you run operations on multiple rows of a Micros
2020

2121
- [`CreateMultiple`](#createmultiple): Creates multiple records of the same type in a single request.
2222
- [`UpdateMultiple`](#updatemultiple): Updates multiple records of the same type in a single request.
23-
- [`UpsertMultiple` (preview)](upsertmultiple.md): Creates or updates multiple records of the same type in a single request.
23+
- [`UpsertMultiple`](upsertmultiple.md): Creates or updates multiple records of the same type in a single request.
2424
- [`DeleteMultiple` (preview)](deletemultiple.md): For elastic tables only. Deletes multiple records of the same type in a single request.
2525

2626
> [!NOTE]
@@ -137,6 +137,7 @@ Updates multiple records of the same type in a single request.
137137

138138
Just like when you update individual records, the data you send with `UpdateMultiple` must contain only the values you're changing. Learn how to [update records with SDK for .NET](org-service/entity-operations-update-delete.md) and [update records with the Web API](webapi/update-delete-entities-using-web-api.md#basic-update).
139139

140+
140141
##### [SDK for .NET](#tab/sdk)
141142

142143
Uses the [UpdateMultipleRequest class](xref:Microsoft.Xrm.Sdk.Messages.UpdateMultipleRequest).
@@ -217,9 +218,161 @@ OData-Version: 4.0
217218

218219
---
219220

220-
#### Duplicate records in the payload
221+
#### Duplicate records in UpdateMultiple Targets parameter
222+
223+
Multiple records with the same primary key or alternate key values in the payload are not supported with `UpdateMultiple`. When more than one record in the `Targets` parameter is uniquely identified by a primary or alternate key, the operation is performed on the first record only. Any subsequent records with the same key value(s) in the payload are ignored. [This behavior is different from `UpsertMultiple`](#duplicate-records-in-upsertmultiple-targets-parameter).
224+
225+
### UpsertMultiple
226+
227+
Use `Upsert` to integrate data with external sources when you don't know whether the table exists in Dataverse or not. `Upsert` operations frequently depend on alternate keys to identify records. Use `UpsertMultiple` to perform `Upsert` operations in bulk.
228+
229+
##### [SDK for .NET](#tab/sdk)
230+
231+
Uses the [UpsertMultipleRequest class](xref:Microsoft.Xrm.Sdk.Messages.UpsertMultipleRequest).
232+
233+
This static `UpsertMultipleExample` method depends on a `samples_bankaccount` table that has a string column named `samples_accountname` configured as an alternate key. It also has a string column named `samples_description`. This code uses the [Entity constructor that sets the keyName and keyValue](use-alternate-key-reference-record.md#using-the-entity-class) to specify the alternate key value.
234+
235+
```csharp
236+
/// <summary>
237+
/// Demonstrates using UpsertMultiple with alternate key values
238+
/// </summary>
239+
/// <param name="service">The authenticated IOrganizationService instance</param>
240+
static void UpsertMultipleExample(IOrganizationService service)
241+
{
242+
var tableLogicalName = "samples_bankaccount";
243+
// samples_accountname string column is configued as an alternate key
244+
// for the samples_bankaccount table
245+
var altKeyColumnLogicalName = "samples_accountname";
246+
247+
// Create one record to update with upsert
248+
service.Create(new Entity(tableLogicalName)
249+
{
250+
Attributes =
251+
{
252+
{altKeyColumnLogicalName, "Record For Update"},
253+
{"samples_description","A record to update using Upsert" }
254+
}
255+
});
256+
257+
// Using the Entity constructor to specify alternate key
258+
Entity toUpdate = new(
259+
entityName: tableLogicalName,
260+
keyName: altKeyColumnLogicalName,
261+
// Same alternate key value as created record.
262+
keyValue: "Record For Update");
263+
toUpdate["samples_description"] = "Updated using Upsert";
264+
265+
Entity toCreate = new(
266+
entityName: tableLogicalName,
267+
keyName: altKeyColumnLogicalName,
268+
keyValue: "Record For Create");
269+
toCreate["samples_description"] = "A record to create using Upsert";
270+
271+
// Add the records to a collection
272+
EntityCollection records = new()
273+
{
274+
EntityName = tableLogicalName,
275+
Entities = { toUpdate, toCreate }
276+
};
277+
278+
// Send the request
279+
UpsertMultipleRequest request = new()
280+
{
281+
Targets = records
282+
};
283+
284+
var response = (UpsertMultipleResponse)service.Execute(request);
285+
286+
// Process the responses:
287+
foreach (UpsertResponse item in response.Results)
288+
{
289+
Console.WriteLine($"Record {(item.RecordCreated ? "Created" : "Updated")}");
290+
}
291+
}
292+
```
293+
294+
**Output:**
295+
296+
```
297+
Record Updated
298+
Record Created
299+
```
221300

222-
Multiple records with the same primary key or alternate key values in the payload are not supported with `UpdateMultiple`. When more than one record in the `Targets` parameter is uniquely identified by a primary or alternate key, the operation is performed on the first record only. Any subsequent records with the same key value(s) in the payload are ignored.
301+
Whether a record is created or updated in this example depends on whether records exist with the matching `sample_keyattribute` value. No data is returned to indicate whether a record was created or updated.
302+
303+
#### SDK examples
304+
305+
Within [Sample: SDK for .NET Use bulk operations](org-service/samples/create-update-multiple.md), look for the [UpsertMultiple project](https://github.com/microsoft/PowerApps-Samples/blob/master/dataverse/orgsvc/C%23-NETCore/BulkOperations/UpsertMultiple/README.md)
306+
307+
##### [Web API](#tab/webapi)
308+
309+
Uses the [UpsertMultiple action](xref:Microsoft.Dynamics.CRM.UpsertMultiple).
310+
311+
> [!IMPORTANT]
312+
>
313+
> - You must set the `@odata.type` property for each item in the `Targets` parameter.
314+
> - The `UpsertMultiple` action returns `204 NoContent`. The `UpsertMultipleResponse` complex type is not returned.
315+
316+
The following example shows using the `UpsertMultiple` action with a standard table named `sample_example`.
317+
These requests identify the records using an alternate key defined using a column named `sample_keyattribute`.
318+
The `@odata.id` annotation identifies the record with a relative URL as described in [Use an alternate key to reference a record](use-alternate-key-reference-record.md)
319+
320+
**Request**
321+
322+
```http
323+
POST [Organization Uri]/api/data/v9.2/sample_examples/Microsoft.Dynamics.CRM.UpsertMultiple
324+
OData-MaxVersion: 4.0
325+
OData-Version: 4.0
326+
If-None-Match: null
327+
Accept: application/json
328+
Authorization: Bearer <access token>
329+
Content-Type: application/json; charset=utf-8
330+
Content-Length: 850
331+
332+
{
333+
"Targets": [
334+
{
335+
"@odata.type": "Microsoft.Dynamics.CRM.sample_example",
336+
"sample_name": "sample record 0000001",
337+
"@odata.id": "sample_examples(sample_keyattribute='0000001')"
338+
},
339+
{
340+
"@odata.type": "Microsoft.Dynamics.CRM.sample_example",
341+
"sample_name": "sample record 0000002",
342+
"@odata.id": "sample_examples(sample_keyattribute='0000002')"
343+
},
344+
{
345+
"@odata.type": "Microsoft.Dynamics.CRM.sample_example",
346+
"sample_name": "sample record 0000003",
347+
"@odata.id": "sample_examples(sample_keyattribute='0000003')"
348+
},
349+
{
350+
"@odata.type": "Microsoft.Dynamics.CRM.sample_example",
351+
"sample_name": "sample record 0000004",
352+
"@odata.id": "sample_examples(sample_keyattribute='0000004')"
353+
354+
}
355+
]
356+
}
357+
```
358+
359+
**Response**
360+
361+
```http
362+
HTTP/1.1 204 NoContent
363+
OData-Version: 4.0
364+
```
365+
---
366+
367+
#### Availability
368+
369+
`UpsertMultiple` is available for tables that support `CreateMultiple` and `UpdateMultiple`. This includes all elastic tables. The queries found in [Availability with standard tables](bulk-operations.md#availability-with-standard-tables) will not return results for `UpsertMultiple`, but you can use them to detect whether a table supports both `CreateMultiple` and `UpdateMultiple`.
370+
371+
These queries will not return results for the `UpsertMultiple` message. A table that supports both `CreateMultiple` and `UpdateMultiple` will support `UpsertMultiple`.
372+
373+
#### Duplicate records in UpsertMultiple Targets parameter
374+
375+
Multiple records with the same primary key or alternate key values in the payload are not supported with `UpsertMultiple`. When more than one record in the `Targets` parameter is uniquely identified by a primary or alternate key, `UpsertMultiple` will return an error. [This behavior is different from `UpdateMultiple`](#duplicate-records-in-updatemultiple-targets-parameter).
223376

224377

225378
## Standard and elastic table usage
@@ -293,8 +446,6 @@ When you use the Web API to perform a bulk operation on an elastic table, you ne
293446
Bulk operation message availability depends on whether you're using standard tables or elastic tables. All elastic tables support the `CreateMultiple`, `UpdateMultiple`, `UpsertMultiple`, and `DeleteMultiple` messages.
294447

295448
See also:
296-
297-
- [UpsertMultiple Availability](upsertmultiple.md#availability)
298449
- [DeleteMultiple Availability](deletemultiple.md#availability)
299450

300451
#### Availability with standard tables
@@ -439,7 +590,9 @@ The default timeout set using ServiceClient is 4 minutes, which is long for any
439590
440591
### Not supported for use in plug-ins
441592

442-
At this time, we don't support using bulk operation messages in plug-ins. More information: [Don't use batch request types in plug-ins and workflow activities](best-practices/business-logic/avoid-batch-requests-plugin.md).
593+
At this time, we don't support using bulk operation messages in plug-in code. More information: [Don't use batch request types in plug-ins and workflow activities](best-practices/business-logic/avoid-batch-requests-plugin.md).
594+
595+
However, you *should* write plug-ins for the `CreateMultiple` and `UpdateMultiple` messages as described in [Write plug-ins for CreateMultiple and UpdateMultiple](write-plugin-multiple-operation.md).
443596

444597
## Troubleshooting common errors
445598

0 commit comments

Comments
 (0)