Dynamics 365 – Use Upsert to Create or Update Records

When working with Dynamics 365, you often need to manipulate the data in the system whether via plugins or web API. But here’s the problem: you don’t always know if the record already exists. If it does, you should update it. If it doesn’t, you should create it.

Instead of manually checking for records and deciding whether to Create or Update, you can use Upsert. It simplifies data integration and ensures that your system stays in sync efficiently.

What is Upsert?

Upsert is a combination of Update and Insert. When you use Upsert:

  • If the record exists → It gets updated.
  • If the record doesn’t exist → A new record is created.

Why Use Upsert?

  • Simplifies logic – No need to check if a record exists before deciding on Create or Update.
  • Optimized for bulk data operations – Useful when importing data from external systems.
  • Uses alternate keys – You can reference records with unique keys instead of primary keys.

Note: If you’re sure the record doesn’t exist, use Create instead of Upsert to avoid performance overhead.

How to Use Upsert in C#

Let’s say you’re syncing product data from an external system into Dataverse. Instead of checking if the product exists, you use Upsert and let the system handle it.

Example: Upserting a Contact Record

We’ll create or update a “Contact” record in Dynamics 365 based on an email address. The scenario could be something like: we are integrating data from an external system, and we want to ensure that every time a contact is processed, we either create a new contact or update an existing one based on the email address.

using Microsoft.Xrm.Sdk;
using Microsoft.Xrm.Sdk.Messages;
using System;

public class ContactUpsertPlugin : IPlugin
{
    public void Execute(IServiceProvider serviceProvider)
    {
        // Get the IOrganizationService instance from the service provider
        IOrganizationServiceFactory serviceFactory = (IOrganizationServiceFactory)serviceProvider.GetService(typeof(IOrganizationServiceFactory));
        IOrganizationService service = serviceFactory.CreateOrganizationService(null); // null to use the context user

        // Example contact data (this would typically come from an external source)
        string email = "john.doe@example.com";
        string firstName = "John";
        string lastName = "Doe";
        string phoneNumber = "123-456-7890";

        // Check if a contact with this email exists using the Upsert logic
        Entity contact = new Entity("contact", "emailaddress1", email);

        contact["firstname"] = firstName;
        contact["lastname"] = lastName;
        contact["telephone1"] = phoneNumber;

        // Prepare the UpsertRequest
        var request = new UpsertRequest
        {
            Target = contact
        };

        try
        {
            // Execute the UpsertRequest
            var response = (UpsertResponse)service.Execute(request);

            // You can log or perform other actions based on the response
            if (response.RecordCreated)
            {
                // Handle newly created record           
            }
            else
            {
                // Handle updated record             
            }
        }
        catch (Exception ex)
        {
            // Handle exceptions appropriately
            throw new InvalidPluginExecutionException($"An error occurred: {ex.Message}");
        }
    }
}

How to use Upsert with JavaScript

The Web API provides a straightforward way to perform Upsert operations using the HTTP PATCH method. Let’s say we’re integrating with an external system and we want to create or update a customer record in Dataverse. We can use the Web API to perform an Upsert operation.

Both Upsert and Update operations are initiated using the HTTP PATCH method against a specified EntitySet resource identified by the keys in the URL. The difference between the two operations lies in the inclusion of the If-Match: * request header.

  • If the If-Match: * request header is included and no resource matches the key values in the URL, the request returns a 404 Not Found status code. This header ensures that the PATCH request is an Update operation.
  • If the If-Match: * request header is not included, the PATCH request is treated as an Upsert operation. If no records matching the keys in the URL are found, a new record is created.

Let’s say we have a table called orders with two alternate key columns: customer_id and order_id. We want to create a new order for a customer with customer_id = 1 and order_id = 1.

PATCH [Organization Uri]/api/data/v9.2/orders(customer_id=1,order_id=1) HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
If-None-Match: null
Accept: application/json
Content-Type: application/json

{
  "order_name": "Order 1"
}

If the order does not exist, a new order will be created. If the order already exists, it will be updated.

Update Operation Example

To update an existing order, we need to include the If-Match: * request header.

PATCH [Organization Uri]/api/data/v9.2/orders(customer_id=1,order_id=1) HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
If-Match: *
Accept: application/json
Content-Type: application/json

{
  "order_name": "Order 1 Updated"
}

If the order does not exist, the request will return a 404 Not Found status code.

Using the Prefer: return=representation Header

To get a different status code in the response to indicate whether the record was created or updated, we can use the Prefer: return=representation header.

PATCH [Organization Uri]/api/data/v9.2/orders(customer_id=2,order_id=2)?$select=order_id HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
If-None-Match: null
Accept: application/json
Prefer: return=representation
Content-Type: application/json

{
  "order_name": "Order 2"
}

This will return a 201 Created status code if the order is created, and a 200 OK status code if the order is updated.

Conclusion

I hope this post has been helpful for you. Remember, you don’t need to use Upsert for every update operation or upsert for every create operation! If you are not sure whether the record exists in the system, it would be more logical to use Upsert.

Leave a comment