Realización de operaciones condicionales mediante la API web

Microsoft Dataverse admite operaciones condicionales que usan el mecanismo estándar de control de versiones de recursos HTTP conocido como ETags. Use operaciones condicionales mediante la API web para optimizar las recuperaciones de registros, limitar las operaciones upsert y aplicar la simultaneidad optimista para evitar sobrescribir los cambios realizados por otros usuarios.

ETags y control de versiones de recursos

El protocolo HTTP define una etiqueta de entidad o ETag para abreviar, para identificar versiones específicas de un recurso. ETags son identificadores opacos cuyos valores exactos dependen de la implementación. Los valores ETag se producen en dos variedades: validación fuerte y débil. La validación fuerte indica que un recurso único, identificado por un URI específico, es idéntico a nivel binario si su valor ETag correspondiente no cambia. La validación débil solo garantiza que la representación de recursos sea semánticamente equivalente para el mismo valor ETag.

Dataverse genera una propiedad de validación @odata.etag débil para cada instancia de entidad y devuelve automáticamente esta propiedad con cada registro de entidad recuperado. Para obtener más información, consulte Recuperación de una fila de tabla mediante la API web.

encabezados If-Match e If-None-Match

Utilice los encabezados If-Match e If-None-Match con valores ETag para comprobar si la versión actual de un recurso coincide con la que recuperó por última vez, coincide con cualquier versión anterior o no coincide con ninguna versión. Estas comparaciones constituyen la base del soporte para operaciones condicionales. Dataverse proporciona ETags para admitir las recuperaciones condicionales, la simultaneidad optimista y las operaciones upsert limitadas.

Advertencia

El código de cliente no debe dar ningún significado al valor específico de una ETag ni a ninguna relación aparente entre ETags más allá de la igualdad o desigualdad. Por ejemplo, no se garantiza que un valor ETag para una versión más reciente de un recurso sea mayor que el valor ETag de una versión anterior. Además, el algoritmo usado para generar nuevos valores ETag podría cambiar sin previo aviso entre las versiones de un servicio.

Recuperaciones condicionales

Etags le ayudan a optimizar las recuperaciones de registros cuando se accede al mismo registro varias veces. Si anteriormente recuperó un registro, pase el valor ETag con el If-None-Match encabezado para solicitar datos solo si cambió desde la última vez que lo recuperó. Si los datos han cambiado, la solicitud devuelve un estado HTTP de 200 OK con los datos más recientes en el cuerpo de la solicitud. Si los datos no cambian, la solicitud devuelve el código de estado HTTP 304 Not Modified para indicar que el registro no se modifica.

El siguiente par de mensajes de ejemplo devuelve datos de un registro de cuenta con accountid igual a 00000000-0000-0000-0000-000000000001 cuando los datos no han cambiado desde que lo recuperó por última vez y el valor Etag era W/"468026".

Solicitud:

GET [Organization URI]/api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001)?$select=accountcategorycode,accountnumber,creditonhold,createdon,numberofemployees,name,revenue   HTTP/1.1  
Accept: application/json  
OData-MaxVersion: 4.0  
OData-Version: 4.0  
If-None-Match: W/"468026"  

Respuesta:

HTTP/1.1 304 Not Modified  
Content-Type: application/json; odata.metadata=minimal  
OData-Version: 4.0  

En las secciones siguientes se describen las limitaciones de uso de las recuperaciones condicionales.

La tabla debe tener habilitada la concurrencia optimista

Compruebe si una tabla tiene habilitada la simultaneidad optimista mediante la siguiente solicitud de API web. Las tablas que tienen habilitada la simultaneidad optimista tienen la propiedad EntityMetadata.IsOptimisticConcurrencyEnabled establecida en true. Use esta dirección URL para recuperar el valor:

GET [Organization URI]/api/data/v9.2/EntityDefinitions(LogicalName='<Entity Logical Name>')?$select=IsOptimisticConcurrencyEnabled

En este ejemplo se recupera el valor de la tabla de contactos:

Solicitud:

GET [Organization URI]/api/data/v9.2/EntityDefinitions(LogicalName='contact')?$select=IsOptimisticConcurrencyEnabled  HTTP/1.1  
Accept: application/json  
OData-MaxVersion: 4.0  
OData-Version: 4.0  

Respuesta:

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

{
   "@odata.context": "[Organization URI]/api/data/v9.2/$metadata#EntityDefinitions(IsOptimisticConcurrencyEnabled)/$entity",
   "MetadataId": "608861bc-50a4-4c5f-a02c-21fe1943e2cf",
   "IsOptimisticConcurrencyEnabled": true
}

La consulta no debe incluir $expand

La etiqueta Etag solo puede detectar si el registro único que se está recuperando ha cambiado. Cuando se usa $expand en la consulta, puede devolver más registros y no es posible detectar si alguno de esos registros ha cambiado. Si la consulta incluye $expand, la solicitud nunca devuelve 304 Not Modified.

La consulta no debe incluir anotaciones

Cuando se incluye el Prefer: odata.include-annotations encabezado en una GET solicitud, el servidor nunca devuelve 304 Not Modified. Los valores de las anotaciones pueden hacer referencia a valores de registros relacionados. Estos registros podrían haber cambiado y el servidor no puede detectar este cambio, por lo que sería incorrecto indicar que no ha cambiado nada.

Limitar las operaciones upsert

Una operación upsert crea un registro si no existe; de lo contrario, actualiza un registro existente. Sin embargo, puede usar ETags para restringir aún más los upserts para evitar las creaciones o evitar actualizaciones.

Evitar crear en upsert

Si va a actualizar los datos y existe la posibilidad de que el registro se haya eliminado intencionadamente, es posible que no quiera volver a crear el registro. Para evitar esta condición, agregue un If-Match encabezado a la solicitud con un valor de *.

Solicitud:

PATCH [Organization URI]/api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001) HTTP/1.1  
Content-Type: application/json  
OData-MaxVersion: 4.0  
OData-Version: 4.0  
If-Match: *  
  
{  
    "name": "Updated Sample Account ",  
    "creditonhold": true,  
    "address1_latitude": 47.639583,  
    "description": "This is the updated description of the sample account",  
    "revenue": 6000000,  
    "accountcategorycode": 2  
}  

Respuesta:

Si el servidor encuentra el registro, obtendrá una respuesta normal con el estado 204 No Content. Si el servidor no encuentra el registro, obtendrá la siguiente respuesta con el estado 404 Not Found.

HTTP/1.1 404 Not Found  
OData-Version: 4.0  
Content-Type: application/json; odata.metadata=minimal  
  
{  
 "error": {  
  "code": "",  
  "message": "account With Id = 00000000-0000-0000-0000-000000000001 Does Not Exist"
 }  
}  

Impedir la actualización en upsert

Si va a insertar datos, es posible que ya exista un registro con el mismo id valor en el sistema. Es posible que no quiera actualizar este registro existente. Para evitar actualizar el registro, agregue un If-None-Match encabezado a la solicitud con un valor de "*".

Solicitud:

PATCH [Organization URI]/api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001) HTTP/1.1  
Content-Type: application/json  
OData-MaxVersion: 4.0  
OData-Version: 4.0  
If-None-Match: *  
  
{  
    "name": "Updated Sample Account ",  
    "creditonhold": true,  
    "address1_latitude": 47.639583,  
    "description": "This is the updated description of the sample account",  
    "revenue": 6000000,  
    "accountcategorycode": 2  
}  

Respuesta:
Si no se encuentra el registro, recibirá una respuesta normal con el estado 204 No Content. Si se encuentra el registro, recibirá la siguiente respuesta con el estado 412 Precondition Failed.

HTTP/1.1 412 Precondition Failed  
OData-Version: 4.0  
Content-Type: application/json; odata.metadata=minimal  
  
{  
  "error":{  
   "code":"",  
   "message":"A record with matching key values already exists."
  }  
}  

Aplicar simultaneidad optimista

Use la concurrencia optimista para detectar si se modificó un registro desde la última vez que lo recuperó. Si el registro que piensa actualizar o eliminar ha cambiado en el servidor desde que lo recuperó, es posible que no desee completar la operación de actualización o eliminación. Con el siguiente patrón, puede detectar esta situación, recuperar la versión más reciente del registro y aplicar los criterios necesarios para volver a evaluar si volver a intentar la operación.

Aplicar simultaneidad optimista al eliminar

La siguiente solicitud de eliminación para una cuenta con accountid de 00000000-0000-0000-0000-000000000001 falla porque el valor de ETag enviado con el encabezado If-Match es diferente del valor actual. Si el valor coincidió, recibirá el estado 204 No Content.

Solicitud:

DELETE [Organization URI]/api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001) HTTP/1.1  
If-Match: W/"470867"  
Accept: application/json  
OData-MaxVersion: 4.0  
OData-Version: 4.0  

Respuesta:

HTTP/1.1 412 Precondition Failed  
Content-Type: application/json; odata.metadata=minimal  
OData-Version: 4.0  
  
{  
  "error":{  
    "code":"","message":"The version of the existing record doesn't match the RowVersion property provided." 
  }  
}  

Aplicar simultaneidad optimista al actualizar

Se produce un error en la siguiente solicitud de actualización para una cuenta con accountid de 00000000-0000-0000-0000-000000000001 porque el valor ETag enviado con la cabecera If-Match es diferente del valor actual. Si el valor ha coincidido, recibirá un estado 204 No Content.

Solicitud:

PATCH [Organization URI]/api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001) HTTP/1.1  
If-Match: W/"470867"  
Accept: application/json  
OData-MaxVersion: 4.0  
OData-Version: 4.0  
  
{"name":"Updated Account Name"}  

Respuesta:

HTTP/1.1 412 Precondition Failed  
Content-Type: application/json; odata.metadata=minimal  
OData-Version: 4.0  
  
{  
  "error":{  
    "code":"","message":"The version of the existing record doesn't match the RowVersion property provided."
  }  
}  

Consulte también

Ejemplo de operaciones condicionales de API web (PowerShell)
Ejemplo de operaciones condicionales de la API web (C#)
Ejemplo de operaciones condicionales de API web (JavaScript del lado cliente)
Realización de operaciones mediante la API web
Redacción de solicitudes HTTP y control de errores