Use Upsert para crear o actualizar un registro

Puede reducir la complejidad que caracteriza a los escenarios de integración de datos mediante el mensaje Upsert. Al cargar datos en Microsoft Dataverse desde un sistema externo, por ejemplo en un escenario de integración de datos en masa, quizá no sepa si ya existe un registro en Dataverse. En tales casos, no sabrá si debe debe usar un mensaje Update o Create. Debe retirar el registro primero para determinar si existe antes de realizar la operación adecuada. Puede reducir esta complejidad y cargar datos en Dataverse de manera más eficiente utilizando el mensaje Upsert.

Hay una penalización del rendimiento con Upsert en lugar de usar Create. Si está seguro de que el registro no existe, use Create.

Nota

Si bien puede usar valores de clave principal con Upsert, generalmente se espera que use claves alternativas porque el caso de uso común son los escenarios de integración de datos. Más información: Usar una clave alternativa para hacer referencia a un registro

Upsert de tabla elástica

El comportamiento de la tabla elástica para Upsert es diferente al de las tablas estándar. Con las tablas elásticas, la operación Upsert no llama al mensaje Create o Update dependiendo de si el registro ya existe o no. Upsert aplica directamente los cambios en la entidad.

  • Si el registro existe: Todos los datos del registro se sobrescriben con los datos de la entidad. No hay ningún evento de Update.
  • Si el registro no existe: se crea un nuevo registro. No hay ningún evento de Create.

Esto tiene implicaciones sobre dónde aplica la lógica empresarial para los eventos. Se puede crear un nuevo registro usando Create o Upsert. Un registro se puede actualizar usando Update o Upsert. Si necesita aplicar lógica consistentemente para Create o Update en tablas elásticas, también debe incluir esa lógica en Upsert. Más información: Upsert un registro en una tabla elástica

Comprensión del proceso de Upsert para tablas estándar

Los mensajes Upsert se procesan en el servidor. El SDK para las clases .NET usa los mismos objetos que se usan en el servidor. Por lo tanto, la siguiente explicación usa el SDK para clases .NET para describir cómo se procesa una instancia UpsertRequest y cómo se devuelve la instancia UpsertResponse.

Los siguientes pasos describen la lógica de procesamiento en el servidor cuando se recibe una UpsertRequest para una tabla estándar:

  1. La instancia UpsertRequest llega con Target Property configurada con una instancia Entity que contiene los datos de una operación Create o Update.
  2. Si existe, Dataverse intentará buscar el registro usando la propiedad Entity.Id de la instancia Entity establecida en la propiedad Target. De lo contrario, usa los valores clave alternativa de Entity.KeyAttributes Property.
  3. Si existe el registro:
    1. Seleccione el Target Entity.Id con el valor de clave principal del registro encontrado.
    2. Elimine todos los datos de la colección Target Entity.Attributes que utilicen las mismas claves utilizadas en la colección Target Entity.KeyAttributes.
    3. Llame a Update.
    4. Establezca la propiedad UpsertResponse.RecordCreated en false.
    5. Cree un EntityReference de la entidad Target como valor para UpsertResponse.Target.
    6. Devuelva la UpsertResponse.
  4. Si el registro no existe:
    1. Copie cualquier dato de Target Entity.KeyAttributes que el Target no tenga en su colección Entity.Attributes en el Target Entity.Attributes.
    2. Llame a Create.
    3. Establezca la UpsertResponse.RecordCreated como true.
    4. Cree una EntityReference desde la entidad Target y el id de resultado de la operación Create como valor para UpsertResponse.Target.
    5. Devuelva la UpsertResponse.

El siguiente diagrama muestra el proceso en el servidor cuando se recibe una UpsertRequest.

flujo del proceso de upsert

Orientación para redactar solicitudes

Cuando se usan claves alternativas para identificar un registro, no se recomienda ni es necesario incluir los datos clave alternativos en la parte de la solicitud que representa los datos que se guardarán.

Si está utilizando la API web y no está familiarizado con el SDK para .NET, el proceso del lado del servidor descrito anteriormente puede ser difícil de seguir. La API web no tiene el mismo modelo de objeto que los objetos SDK que se usan en la descripción y el diagrama anterior, pero los datos se pueden asignar como se muestra en la siguiente tabla.

API Web SDK de Descripción
Valores de clave en URL Entity.KeyAttributes Property Contiene los datos de clave alternativa para identificar el registro.
Cuerpo de la solicitud La Entity configurada en UpsertRequest.Target Property. Contiene los datos que se utilizarán para Create o Update.

Aunque estas solicitudes se procesan en el servidor como se describe anteriormente, puede pensarlo de esta manera:

  • Si el registro existe: El conjunto de datos en el cuerpo de la solicitud para esos valores clave alternativos en la URL se eliminaron, así que no tiene sentido incluirlos. Esta práctica garantiza que no pueda actualizar los valores clave alternativos de un registro cuando usa esos valores clave alternativos para identificarlo. Puede cambiar los valores de clave alternativa utilizando la clave principal o un conjunto diferente de claves alternativas.
  • Si el registro no existe: Cualquier valor clave alternativo establecido en el cuerpo de la solicitud se usa para crear el nuevo registro, incluso si los datos son diferentes a los valores especificados por las claves alternativas en la URL. Si no hay datos clave alternativos en el cuerpo de la solicitud, los datos clave alternativos de la URL se copian en el cuerpo de la solicitud. Para evitar una situación en la que los valores clave en la URL y los valores clave correspondientes en el cuerpo no coincidan, es mejor no incluirlos en el cuerpo.

Uso de la API web

Con la API web, los mensajes Upsert y Update se inician usando http PATCH frente a un recurso EntitySet especificado e identificado por las claves en la URL.

La diferencia entre Upsert y Update se define por si el encabezado de solicitud If-Match: * está incluido. Si el encabezado de solicitud If-Match: * está incluido y ningún recurso coincide con los valores clave en la URL, la solicitud devuelve un código de estado 404 Not Found. El encabezado de solicitud If-Match: * asegura que la solicitud PATCH sea una operación Update.

Si no se incluye el encabezado de la solicitud If-Match: *, la solicitud PATCH se trata como una Upsert y se crea un nuevo registro si no hay registros que coincidan con las claves que se encuentran en las URL. Sin embargo, a diferencia del SDK, la respuesta no le indica si se creó un registro. La respuesta de estado es 204 No Content en cualquier caso.

Si incluye un encabezado de solicitud Prefer: return=representation, el sistema devuelve un estado 201 Created para Create y un estado 200 OK para Update. Agregar este encabezado agrega una operación adicional Retrieve por lo que tiene un impacto en el rendimiento. Si utiliza esta opción, asegúrese de que la opción de consulta $select que agregue solo incluya el valor de clave principal. Más información:

Con una solicitud PATCH también puede incluir el encabezado de solicitud If-None-Match: * para bloquear un Update si solo desea crear registros. Más información:Limitar operaciones de upsert.

Código de ejemplo de API web

Los siguientes ejemplos muestran operaciones Upsert utilizando una tabla con dos columnas de clave alternativa:

Crear con Upsert

Esta solicitud crea un registro.

Solicitud:

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

{ "example_name": "2:2" }

Respuesta:

HTTP/1.1 204 No Content
OData-Version: 4.0
OData-EntityId: [Organization Uri]/api/data/v9.2/example_records(example_key1=2,example_key2=2)

Actualizar con Upsert

Esta solicitud actualiza el registro creado por la solicitud anterior.

Solicitud:

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

{ "example_name": "2:2 Updated" }

Respuesta:

HTTP/1.1 204 No Content
OData-Version: 4.0
OData-EntityId: [Organization Uri]/api/data/v9.2/example_records(example_key1=2,example_key2=2)

Nota

La respuesta es idéntica para las operaciones Crear o Actualizar.

Create con Upsert y preferencia return=representation

Cuando usa el encabezado Prefer: return=representation puede obtener un código de estado diferente en la respuesta para indicar si el registro se creó o actualizó.

La siguiente solicitud crea un nuevo registro y devuelve el estado 201 Created.

Solicitud:

PATCH [Organization Uri]/api/data/v9.2/example_records(example_key1=3,example_key2=3)?$select=example_recordid 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

{ "example_name": "3:3" }

Respuesta:

HTTP/1.1 201 Created
Content-Type: application/json; odata.metadata=minimal
ETag: W/"71004878"
Preference-Applied: return=representation
OData-Version: 4.0

{
  "@odata.context": "[Organization Uri]/api/data/v9.2/$metadata#example_records(example_recordid)/$entity",
  "@odata.etag": "W/\"71004878\"",
  "example_recordid": "ef0d112e-d70e-ed11-82e5-00224822577b"
}

Actualizar con Upsert y preferencia devolución=representación

Esta solicitud actualiza el registro creado por la solicitud anterior y devuelve el estado 200 OK para mostrar que se trataba de una operación de actualización.

Solicitud:

PATCH [Organization Uri]/api/data/v9.2/example_records(example_key1=3,example_key2=3)?$select=example_recordid 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

{ "example_name": "3:3 Updated" }

Respuesta:

HTTP/1.1 200 OK
Content-Type: application/json; odata.metadata=minimal
ETag: W/"71004880"
OData-Version: 4.0

{
  "@odata.context": "[Organization Uri]/api/data/v9.2/$metadata#example_records(example_recordid)/$entity",
  "@odata.etag": "W/\"71004880\"",
  "example_recordid": "ef0d112e-d70e-ed11-82e5-00224822577b"
}

Uso del SDK para .NET

Su aplicación de cliente utiliza IOrganizationService.Execute Method con una instancia UpsertRequest que tiene el conjunto Target Property con una instancia Entity que contiene los datos para una operación Create o Update. La instancia Entity normalmente tendrá Entity.KeyAttributes Property configurada con valores utilizados para identificar el registro mediante claves alternativas.

UpsertResponse.RecordCreated Property le dice si el registro fue creado, y UpsertResponse.Target contiene una referencia al registro que se creó o actualizó.

Código de muestra de SDK para .NET

El archivo SampleMethod.cs en la muestra Insertar registro usando Upsert contiene el siguiente método ProcessUpsert para aplicar el mensaje UpsertRequest en los contenidos de un archivo XML para crear nuevos registros o actualizar los que ya existen.

public static void ProcessUpsert(CrmServiceClient service, String Filename)
{
    Console.WriteLine("Executing upsert operation.....");
    XmlTextReader tr = new XmlTextReader(Filename);
    XmlDocument xdoc = new XmlDocument();
    xdoc.Load(tr);
    XmlNodeList xnlNodes = xdoc.DocumentElement.SelectNodes("/products/product");

    foreach (XmlNode xndNode in xnlNodes)
    {
        String productCode = xndNode.SelectSingleNode("Code").InnerText;
        String productName = xndNode.SelectSingleNode("Name").InnerText;
        String productCategory = xndNode.SelectSingleNode("Category").InnerText;
        String productMake = xndNode.SelectSingleNode("Make").InnerText;

        //use alternate key for product
        Entity productToCreate = new Entity("sample_product", "sample_productcode", productCode);

        productToCreate["sample_name"] = productName;
        productToCreate["sample_category"] = productCategory;
        productToCreate["sample_make"] = productMake;
        var request = new UpsertRequest()
        {
            Target = productToCreate
        };

        try
        {
            // Execute UpsertRequest and obtain UpsertResponse.
            var response = (UpsertResponse)service.Execute(request);
            if (response.RecordCreated)
                Console.WriteLine("New record {0} is created!", productName);
            else
                Console.WriteLine("Existing record {0} is updated!", productName);
        }

        // Catch any service fault exceptions that Dataverse throws.
        catch (FaultException<Microsoft.Xrm.Sdk.OrganizationServiceFault>)
        {
            throw;
        }
    }
}

Vea también

Uso del seguimiento de cambios para sincronizar los datos con sistemas externos
Definir claves alternativas para una tabla
Usar una clave alternativa para hacer referencia a un registro

Nota

¿Puede indicarnos sus preferencias de idioma de documentación? Realice una breve encuesta. (tenga en cuenta que esta encuesta está en inglés)

La encuesta durará unos siete minutos. No se recopilan datos personales (declaración de privacidad).