Ejecute las operaciones por lotes mediante API web

Puede agrupar varias operaciones en una sola solicitud HTTP con una operación por lotes. Estas operaciones se realizan secuencialmente en el orden en que se especifican. El orden de las respuestas coincide con el orden de las solicitudes en la operación por lotes.

El formato para enviar solicitudes $batch se define en esta sección de la especificación de OData: 11.7 Solicitudes por lotes. El contenido de este tema resume los requisitos de especificación y proporciona a Dataverse ejemplos e información específica.

Cuándo usar solicitudes por lotes

Las solicitudes por lotes proporcionan dos capacidades que se pueden usar juntas:

  • Puede enviar solicitudes para múltiples operaciones con una sola solicitud HTTP.

    • La solicitudes por lotes pueden contener hasta 1000 solicitudes individuales y no pueden contener otras solicitudes por lotes.
    • Las solicitudes de API web $batch son equivalentes al mensaje ExecuteMultiple disponible en el SDK para .NET. Más información: Ejemplo: ejecutar varias solicitudes usando SDK para .NET.
  • Puede agrupar solicitudes de operaciones para que se incluyan como una sola transacción mediante Conjuntos de cambios.

    • Es posible que desee crear, actualizar o eliminar un conjunto de registros relacionados de una manera que garantice que todas las operaciones se realicen correctamente o fallen como grupo.
    • Las solicitudes de API web $batch que usan conjuntos de cambios son equivalentes al mensaje ExecuteTransaction disponible en el SDK para .NET. Más información: Ejecutar mensajes en una sola transacción de la base de datos

    Nota

    Recuerde que las entidades asociadas se pueden crear en una sola operación más fácilmente que usando una solicitud por lotes. Más información: Crear filas de tabla relacionadas en una sola operación

Las solicitudes por lotes también se utilizan a veces para enviar solicitudes GET en las que la longitud de la URL puede exceder la longitud máxima permitida de la URL. La gente utiliza solicitudes por lotes porque la URL de la solicitud se incluye en el cuerpo del mensaje, donde se permite una URL de hasta 64 KB (65 536 caracteres). El envío de consultas complejas mediante FetchXml puede generar direcciones URL largas. Más información: Uso de FetchXML con una solicitud en lote.

En comparación con otras operaciones que se pueden realizar con la API web, las solicitudes por lotes son más difíciles de redactar. Los cuerpos de solicitud y respuesta sin procesar son esencialmente un documento de texto que debe cumplir requisitos específicos. Para accedder a los datos en una respuesta, necesita analizar el texto de la respuesta o localizar una biblioteca de código auxiliar para tener acceso a los datos de la respuesta. Consulte Métodos auxiliares de .NET.

Solicitudes por lotes

Use una solicitud POST para enviar una operación por lotes que contenga varias solicitudes.

La solicitud POST que contiene el lote debe tener un encabezado Content-Type con un valor establecido como multipart/mixed con un conjunto de boundary para incluir el identificador del lote utilizando este patrón:

POST [Organization Uri]/api/data/v9.2/$batch HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
If-None-Match: null
Accept: application/json
Content-Type: multipart/mixed; boundary="batch_<unique identifier>"

El identificador único no necesita ser un GUID, pero debe ser único.

Cada elemento dentro del lote debe ir precedido del identificador de lote con un encabezado Content-Type y Content-Transfer-Encoding como el siguiente:

--batch_<unique identifier>
Content-Type: application/http
Content-Transfer-Encoding: binary

Importante

Solo los elementos de carga útil con un identificador de lote que coincida con el identificador de lote enviado en el se ejecutará el encabezado Content-Type. Si ningún elemento de carga útil utiliza el identificador de lote Content-Type, la solicitud por lotes se realizará correctamente sin ejecutar ningún elemento de carga útil.

Debe incluir cualquier otro encabezado HTTP para cada elemento del lote para controlar el comportamiento de esa solicitud. Los encabezados aplicados a la operación $batch no se aplicarán a cada elemento. Por ejemplo, si incluye una solicitud GET y desea solicitar anotaciones, debe agregar el correspondiente encabezado Prefer: odata.include-annotations="*" de cada artículo.

El final de la solicitud en lote debe contener un indicador de finalización como el siguiente:

--batch_<unique identifier>--

Nota

El protocolo HTTP requiere que todos los finales de línea en las cargas útiles de solicitud $batch sean CRLF. Otros finales de línea pueden provocar errores de deserialización. Por ejemplo: System.ArgumentException: Stream was not readable.. Si no puede utilizar CRLF, puede agregar dos finales de línea que no sean CRLF al final de la carga útil de la solicitud para resolver la mayoría de los errores de deserialización.

El siguiente ejemplo es una solicitud por lotes sin conjuntos de cambios. Este ejemplo:

  • Crea tres registros de tareas asociados a una cuenta con accountid igual a 00000000-0000-0000-0000-000000000001.
  • Recupera los registros de tareas asociados con la cuenta.

Solicitud:

POST [Organization Uri]/api/data/v9.2/$batch HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
If-None-Match: null
Accept: application/json
Content-Type: multipart/mixed; boundary="batch_80dd1615-2a10-428a-bb6f-0e559792721f"

--batch_80dd1615-2a10-428a-bb6f-0e559792721f
Content-Type: application/http
Content-Transfer-Encoding: binary

POST /api/data/v9.2/tasks HTTP/1.1
Content-Type: application/json; type=entry

{
  "subject": "Task 1 in batch",
  "regardingobjectid_account_task@odata.bind": "accounts(00000000-0000-0000-0000-000000000001)"
}
--batch_80dd1615-2a10-428a-bb6f-0e559792721f
Content-Type: application/http
Content-Transfer-Encoding: binary

POST /api/data/v9.2/tasks HTTP/1.1
Content-Type: application/json; type=entry

{
  "subject": "Task 2 in batch",
  "regardingobjectid_account_task@odata.bind": "accounts(00000000-0000-0000-0000-000000000001)"
}
--batch_80dd1615-2a10-428a-bb6f-0e559792721f
Content-Type: application/http
Content-Transfer-Encoding: binary

POST /api/data/v9.2/tasks HTTP/1.1
Content-Type: application/json; type=entry

{
  "subject": "Task 3 in batch",
  "regardingobjectid_account_task@odata.bind": "accounts(00000000-0000-0000-0000-000000000001)"
}
--batch_80dd1615-2a10-428a-bb6f-0e559792721f
Content-Type: application/http
Content-Transfer-Encoding: binary

GET /api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001)/Account_Tasks?$select=subject HTTP/1.1


--batch_80dd1615-2a10-428a-bb6f-0e559792721f--

Respuestas en lote

Cuando tiene éxito, la respuesta por lotes devuelve el estado HTTP 200 OK y cada elemento de la respuesta está separado por un valor de identificador único Guid que no es el mismo que el valor de la solicitud por lotes.

--batchresponse_<unique identifier>
Content-Type: application/http
Content-Transfer-Encoding: binary

El final de la respuesta del lote contiene un indicador de finalización como el siguiente ejemplo:

--batchresponse_<unique identifier>--

El siguiente ejemplo es la respuesta al ejemplo de solicitud por lotes anterior.

Respuesta:

HTTP/1.1 200 OK
OData-Version: 4.0

--batchresponse_01346794-f2e2-4d45-8cc2-f97e09fe8916
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 204 No Content
OData-Version: 4.0
Location: [Organization Uri]/api/data/v9.2/tasks(d31ba648-c592-ed11-aad1-000d3a993550)
OData-EntityId: [Organization Uri]/api/data/v9.2/tasks(d31ba648-c592-ed11-aad1-000d3a993550)


--batchresponse_01346794-f2e2-4d45-8cc2-f97e09fe8916
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 204 No Content
OData-Version: 4.0
Location: [Organization Uri]/api/data/v9.2/tasks(d41ba648-c592-ed11-aad1-000d3a993550)
OData-EntityId: [Organization Uri]/api/data/v9.2/tasks(d41ba648-c592-ed11-aad1-000d3a993550)


--batchresponse_01346794-f2e2-4d45-8cc2-f97e09fe8916
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 204 No Content
OData-Version: 4.0
Location: [Organization Uri]/api/data/v9.2/tasks(d51ba648-c592-ed11-aad1-000d3a993550)
OData-EntityId: [Organization Uri]/api/data/v9.2/tasks(d51ba648-c592-ed11-aad1-000d3a993550)


--batchresponse_01346794-f2e2-4d45-8cc2-f97e09fe8916
Content-Type: application/http
Content-Transfer-Encoding: binary

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

{
  "@odata.context": "[Organization Uri]/api/data/v9.2/$metadata#tasks(subject)",
  "value": [
    {
      "@odata.etag": "W/\"77180907\"",
      "subject": "Task 1 in batch",
      "activityid": "d31ba648-c592-ed11-aad1-000d3a993550"
    },
    {
      "@odata.etag": "W/\"77180910\"",
      "subject": "Task 2 in batch",
      "activityid": "d41ba648-c592-ed11-aad1-000d3a993550"
    },
    {
      "@odata.etag": "W/\"77180913\"",
      "subject": "Task 3 in batch",
      "activityid": "d51ba648-c592-ed11-aad1-000d3a993550"
    }
  ]
}
--batchresponse_01346794-f2e2-4d45-8cc2-f97e09fe8916--

Conjuntos de cambios

Además de solicitudes individuales, una solicitud en lote puede incluir conjuntos de cambios. Cuando varias operaciones están contenidas en un conjunto de cambios, todas las operaciones se consideran atómicas. Una operación atómica significa que si alguna de las operaciones falla, todas las operaciones completadas se revierten.

Nota

Las solicitudes GET no están permitidas dentro de los conjuntos de cambios. Una operación GET no debe cambiar los datos, por lo tanto, no pertenecen a un conjunto de cambios.

Como una solicitud en lote, los conjuntos de cambios deben tener un encabezado Content-Type con un valor establecido como multipart/mixed con un conjunto boundary para incluir el identificador del conjunto de cambios utilizando este patrón:

Content-Type: multipart/mixed; boundary="changeset_<unique identifier>"

El identificador único no necesita ser un GUID, pero debe ser único. Cada elemento dentro del conjunto de cambios debe ir precedido del identificador del conjunto de cambios con un encabezado Content-Type y Content-Transfer-Encoding como el siguiente ejemplo:

--changeset_<unique identifier>
Content-Type: application/http
Content-Transfer-Encoding: binary

Los conjuntos de cambios también pueden incluir un encabezado Content-ID con un valor único. Este valor, cuando va precedido de $, representa una variable que contiene la Uri para cualquier entidad creada en esa operación. Por ejemplo, cuando establece el valor de 1, puede hacer referencia a esa entidad usando $1 más adelante en el conjunto de cambios. Más información: URI de referencia en una operación

El final del conjunto de cambios debe contener un indicador de finalización como el siguiente ejemplo:

--changeset_<unique identifier>--

El siguiente ejemplo muestra el uso de un conjunto de cambios para:

  • Agrupar la creación de tres tareas asociadas a una cuenta con un valor accountid de 00000000-0000-0000-0000-000000000001.
  • Recuperar las cuentas creadas mediante una solicitud GET fuera del conjunto de cambios.

Solicitud:

POST [Organization Uri]/api/data/v9.2/$batch HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
If-None-Match: null
Accept: application/json
Content-Type: multipart/mixed; boundary="batch_22975cad-7f57-410d-be15-6363209367ea"

--batch_22975cad-7f57-410d-be15-6363209367ea
Content-Type: multipart/mixed; boundary="changeset_246e6bfe-89a4-4c77-b293-7a433f082e8a"

--changeset_246e6bfe-89a4-4c77-b293-7a433f082e8a
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 1

POST /api/data/v9.2/tasks HTTP/1.1
Content-Type: application/json; type=entry

{
  "subject": "Task 1 in batch",
  "regardingobjectid_account_task@odata.bind": "accounts(00000000-0000-0000-0000-000000000001)"
}
--changeset_246e6bfe-89a4-4c77-b293-7a433f082e8a
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 2

POST /api/data/v9.2/tasks HTTP/1.1
Content-Type: application/json; type=entry

{
  "subject": "Task 2 in batch",
  "regardingobjectid_account_task@odata.bind": "accounts(00000000-0000-0000-0000-000000000001)"
}
--changeset_246e6bfe-89a4-4c77-b293-7a433f082e8a
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 3

POST /api/data/v9.2/tasks HTTP/1.1
Content-Type: application/json; type=entry

{
  "subject": "Task 3 in batch",
  "regardingobjectid_account_task@odata.bind": "accounts(00000000-0000-0000-0000-000000000001)"
}
--changeset_246e6bfe-89a4-4c77-b293-7a433f082e8a--

--batch_22975cad-7f57-410d-be15-6363209367ea
Content-Type: application/http
Content-Transfer-Encoding: binary

GET /api/data/v9.2/accounts(00000000-0000-0000-0000-000000000001)/Account_Tasks?$select=subject HTTP/1.1


--batch_22975cad-7f57-410d-be15-6363209367ea--

Respuesta:

HTTP/1.1 200 OK
OData-Version: 4.0

--batchresponse_f27ef42d-51b0-4685-bac9-f468f844de2f
Content-Type: multipart/mixed; boundary=changesetresponse_64cc3fff-023a-45b0-b29d-df21583ffa15

--changesetresponse_64cc3fff-023a-45b0-b29d-df21583ffa15
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 1

HTTP/1.1 204 No Content
OData-Version: 4.0
Location: [Organization Uri]/api/data/v9.2/tasks(e73ffc82-e292-ed11-aad1-000d3a9933c9)
OData-EntityId: [Organization Uri]/api/data/v9.2/tasks(e73ffc82-e292-ed11-aad1-000d3a9933c9)


--changesetresponse_64cc3fff-023a-45b0-b29d-df21583ffa15
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 2

HTTP/1.1 204 No Content
OData-Version: 4.0
Location: [Organization Uri]/api/data/v9.2/tasks(e83ffc82-e292-ed11-aad1-000d3a9933c9)
OData-EntityId: [Organization Uri]/api/data/v9.2/tasks(e83ffc82-e292-ed11-aad1-000d3a9933c9)


--changesetresponse_64cc3fff-023a-45b0-b29d-df21583ffa15
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 3

HTTP/1.1 204 No Content
OData-Version: 4.0
Location: [Organization Uri]/api/data/v9.2/tasks(e93ffc82-e292-ed11-aad1-000d3a9933c9)
OData-EntityId: [Organization Uri]/api/data/v9.2/tasks(e93ffc82-e292-ed11-aad1-000d3a9933c9)


--changesetresponse_64cc3fff-023a-45b0-b29d-df21583ffa15--
--batchresponse_f27ef42d-51b0-4685-bac9-f468f844de2f
Content-Type: application/http
Content-Transfer-Encoding: binary

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

{
  "@odata.context": "[Organization Uri]/api/data/v9.2/$metadata#tasks(subject)",
  "value": [
    {
      "@odata.etag": "W/\"77181173\"",
      "subject": "Task 1 in batch",
      "activityid": "e73ffc82-e292-ed11-aad1-000d3a9933c9"
    },
    {
      "@odata.etag": "W/\"77181176\"",
      "subject": "Task 2 in batch",
      "activityid": "e83ffc82-e292-ed11-aad1-000d3a9933c9"
    },
    {
      "@odata.etag": "W/\"77181179\"",
      "subject": "Task 3 in batch",
      "activityid": "e93ffc82-e292-ed11-aad1-000d3a9933c9"
    }
  ]
}
--batchresponse_f27ef42d-51b0-4685-bac9-f468f844de2f--

Hacer referencia a URI en una operación

En los conjuntos de cambios, puede usar $parameter, como $1, $2, etc., para hacer referencia a URI devueltos para nuevas entidades creadas anteriormente en el mismo conjunto de cambios. Para obtener más información, consulte la especificación OData v4.0: 11.7.3.1 Solicitudes de referencia en un conjunto de cambios.

Esta sección muestra diferentes ejemplos sobre cómo $parameter se puede usar en el cuerpo de la solicitud de una operación por lotes para hacer referencia a URI.

Hacer referencia a URI en el cuerpo de la solicitud

El siguiente ejemplo muestra cómo dos referencias de URI se pueden usar en una sola operación.

Solicitud:

POST [Organization URI]/api/data/v9.2/$batch HTTP/1.1
Content-Type:  multipart/mixed;boundary=batch_AAA123
Accept:  application/json
OData-MaxVersion:  4.0
OData-Version:  4.0

--batch_AAA123
Content-Type: multipart/mixed; boundary=changeset_dd81ccab-11ce-4d57-b91d-12c4e25c3cab

--changeset_dd81ccab-11ce-4d57-b91d-12c4e25c3cab
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 1

POST [Organization URI]/api/data/v9.2/leads HTTP/1.1
Content-Type: application/json

{
    "firstname":"first name",
    "lastname":"last name"
}

--changeset_dd81ccab-11ce-4d57-b91d-12c4e25c3cab
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 2

POST [Organization URI]/api/data/v9.2/contacts HTTP/1.1
Content-Type: application/json

{"firstname":"first name"}

--changeset_dd81ccab-11ce-4d57-b91d-12c4e25c3cab
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 3

POST [Organization URI]/api/data/v9.2/accounts HTTP/1.1
Content-Type: application/json

{
    "name":"IcM Account",
    "originatingleadid@odata.bind":"$1",
    "primarycontactid@odata.bind":"$2"
}

--changeset_dd81ccab-11ce-4d57-b91d-12c4e25c3cab--
--batch_AAA123--

Respuesta:

HTTP/1.1 200 OK
OData-Version: 4.0

--batchresponse_3cace264-86ea-40fe-83d3-954b336c0f4a
Content-Type: multipart/mixed; boundary=changesetresponse_1a5db8a1-ec98-42c4-81f6-6bc6adcfa4bc

--changesetresponse_1a5db8a1-ec98-42c4-81f6-6bc6adcfa4bc
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 1

HTTP/1.1 204 No Content
OData-Version: 4.0
Location: [Organization URI]/api/data/v9.2/leads(425195a4-7a75-e911-a97a-000d3a34a1bd)
OData-EntityId: [Organization URI]/api/data/v9.2/leads(425195a4-7a75-e911-a97a-000d3a34a1bd)

--changesetresponse_1a5db8a1-ec98-42c4-81f6-6bc6adcfa4bc
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 2

HTTP/1.1 204 No Content
OData-Version: 4.0
Location: [Organization URI]/api/data/v9.2/contacts(495195a4-7a75-e911-a97a-000d3a34a1bd)
OData-EntityId: [Organization URI]/api/data/v9.2/contacts(495195a4-7a75-e911-a97a-000d3a34a1bd)

--changesetresponse_1a5db8a1-ec98-42c4-81f6-6bc6adcfa4bc
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 3

HTTP/1.1 204 No Content
OData-Version: 4.0
Location: [Organization URI]/api/data/v9.2/accounts(4f5195a4-7a75-e911-a97a-000d3a34a1bd)
OData-EntityId: [Organization URI]/api/data/v9.2/accounts(4f5195a4-7a75-e911-a97a-000d3a34a1bd)

--changesetresponse_1a5db8a1-ec98-42c4-81f6-6bc6adcfa4bc--
--batchresponse_3cace264-86ea-40fe-83d3-954b336c0f4a--

Hacer referencia a URI en dirección URL de la solicitud

El ejemplo ofrecido a continuación muestra cómo puede hacer referencia a un URI usando $1 en la dirección URL de una solicitud posterior.

Solicitud:

POST [Organization URI]/api/data/v9.2/$batch HTTP/1.1
Content-Type:  multipart/mixed;boundary=batch_AAA123
Accept:  application/json
OData-MaxVersion:  4.0
OData-Version:  4.0

--batch_AAA123
Content-Type: multipart/mixed; boundary=changeset_dd81ccab-11ce-4d57-b91d-12c4e25c3cab

--changeset_dd81ccab-11ce-4d57-b91d-12c4e25c3cab
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 1

POST [Organization URI]/api/data/v9.2/contacts HTTP/1.1
Content-Type: application/json

{
  "firstname":"First Name",
  "lastname":"Last name"
}

--changeset_dd81ccab-11ce-4d57-b91d-12c4e25c3cab
Content-Transfer-Encoding: binary
Content-Type: application/http
Content-ID: 2

PUT $1/lastname HTTP/1.1
Content-Type: application/json

{
  "value":"BBBBB"
}

--changeset_dd81ccab-11ce-4d57-b91d-12c4e25c3cab--
--batch_AAA123--

Respuesta:

HTTP/1.1 200 OK
OData-Version: 4.0

--batchresponse_2cb48f48-39a8-41ea-aa52-132fa8ab3c2d
Content-Type: multipart/mixed; boundary=changesetresponse_d7528170-3ef3-41bd-be8e-eac971a8d9d4

--changesetresponse_d7528170-3ef3-41bd-be8e-eac971a8d9d4
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 1

HTTP/1.1 204 No Content
OData-Version: 4.0
Location:[Organization URI]/api/data/v9.2/contacts(f8ea5d2c-8c75-e911-a97a-000d3a34a1bd)
OData-EntityId:[Organization URI]/api/data/v9.2/contacts(f8ea5d2c-8c75-e911-a97a-000d3a34a1bd)


--changesetresponse_d7528170-3ef3-41bd-be8e-eac971a8d9d4
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 2

HTTP/1.1 204 No Content
OData-Version: 4.0


--changesetresponse_d7528170-3ef3-41bd-be8e-eac971a8d9d4--
--batchresponse_2cb48f48-39a8-41ea-aa52-132fa8ab3c2d--

Hacer referencia a URI en la dirección URL y el cuerpo de la solicitud usando @odata.id

El ejemplo siguiente muestra cómo vincular un registro de entidad Contacto a un registro de entidad Cuenta. Al URI del registro de entidad Cuenta se hace referencia como $1 y al URI del registro de entidad Contacto se hace referencia como $2.

Solicitud:

POST [Organization URI]/api/data/v9.2/$batch HTTP/1.1
Content-Type:multipart/mixed;boundary=batch_AAA123
Accept:application/json
OData-MaxVersion:4.0
OData-Version:4.0

--batch_AAA123
Content-Type: multipart/mixed; boundary=changeset_dd81ccab-11ce-4d57-b91d-12c4e25c3cab

--changeset_dd81ccab-11ce-4d57-b91d-12c4e25c3cab
Content-Type:application/http
Content-Transfer-Encoding:binary
Content-ID:1

POST [Organization URI]/api/data/v9.2/accounts HTTP/1.1
Content-Type: application/json

{ "name":"Account Name"}

--changeset_dd81ccab-11ce-4d57-b91d-12c4e25c3cab
Content-Type:application/http
Content-Transfer-Encoding:binary
Content-ID:2

POST [Organization URI]/api/data/v9.2/contacts HTTP/1.1
Content-Type:application/json

{ "firstname":"Contact first name"}

--changeset_dd81ccab-11ce-4d57-b91d-12c4e25c3cab
Content-Type:application/http
Content-Transfer-Encoding:binary
Content-ID:3

PUT $1/primarycontactid/$ref HTTP/1.1
Content-Type:application/json

{"@odata.id":"$2"}

--changeset_dd81ccab-11ce-4d57-b91d-12c4e25c3cab--
--batch_AAA123--

Respuesta:

HTTP/1.1 200 OK
OData-Version: 4.0

--batchresponse_0740a25c-d8e1-41a5-9202-1b50a297864c
Content-Type: multipart/mixed; boundary=changesetresponse_19ca0da8-d8bb-4273-a3f7-fe0d0fadfe5f

--changesetresponse_19ca0da8-d8bb-4273-a3f7-fe0d0fadfe5f
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 1

HTTP/1.1 204 No Content
OData-Version: 4.0
Location:[Organization URI]/api/data/v9.2/accounts(3dcf8c02-8c75-e911-a97a-000d3a34a1bd)
OData-EntityId:[Organization URI]/api/data/v9.2/accounts(3dcf8c02-8c75-e911-a97a-000d3a34a1bd)

--changesetresponse_19ca0da8-d8bb-4273-a3f7-fe0d0fadfe5f
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 2

HTTP/1.1 204 No Content
OData-Version: 4.0
Location:[Organization URI]/api/data/v9.2/contacts(43cf8c02-8c75-e911-a97a-000d3a34a1bd)
OData-EntityId:[Organization URI]/api/data/v9.2/contacts(43cf8c02-8c75-e911-a97a-000d3a34a1bd)

--changesetresponse_19ca0da8-d8bb-4273-a3f7-fe0d0fadfe5f
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 3

HTTP/1.1 204 No Content
OData-Version: 4.0

--changesetresponse_19ca0da8-d8bb-4273-a3f7-fe0d0fadfe5f--
--batchresponse_0740a25c-d8e1-41a5-9202-1b50a297864c--

Hacer referencia a URI en propiedades de dirección URL y navegación

El ejemplo siguiente muestra cómo usar el URI de la organización de un registro de contacto y vincularlo a un registro de cuenta utilizando la propiedad de navegación de un solo valor primarycontactid. Al URI del registro de entidad Cuenta se hace referencia como $1 y al URI del registro de entidad Contacto se hace referencia como $2 en la solicitud PATCH.

Solicitud:

POST [Organization URI]/api/data/v9.2/$batch HTTP/1.1
Content-Type:multipart/mixed;boundary=batch_AAA123
Accept:application/json
OData-MaxVersion:4.0
OData-Version:4.0

--batch_AAA123
Content-Type: multipart/mixed; boundary=changeset_dd81ccab-11ce-4d57-b91d-12c4e25c3cab

--changeset_dd81ccab-11ce-4d57-b91d-12c4e25c3cab
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 1

POST [Organization URI]/api/data/v9.2/accounts HTTP/1.1
Content-Type: application/json

{ "name":"Account name"}

--changeset_dd81ccab-11ce-4d57-b91d-12c4e25c3cab
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 2

POST [Organization URI]/api/data/v9.2/contacts HTTP/1.1
Content-Type: application/json

{
  "firstname":"Contact first name"
}

--changeset_dd81ccab-11ce-4d57-b91d-12c4e25c3cab
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 3

PATCH $1 HTTP/1.1
Content-Type: application/json

{
  "primarycontactid@odata.bind":"$2"
}

--changeset_dd81ccab-11ce-4d57-b91d-12c4e25c3cab--
--batch_AAA123--

Respuesta:

HTTP/1.1 200 OK
OData-Version: 4.0

--batchresponse_9595d3ae-48f6-414f-a3aa-a3a33559859e
Content-Type: multipart/mixed; boundary=changesetresponse_0c1567a5-ad0d-48fa-b81d-e6db05cad01c

--changesetresponse_0c1567a5-ad0d-48fa-b81d-e6db05cad01c
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 1

HTTP/1.1 204 No Content
OData-Version: 4.0
Location: [Organization URI]/api/data/v9.2/accounts(6cd81853-7b75-e911-a97a-000d3a34a1bd)
OData-EntityId: [Organization URI]/api/data/v9.2/accounts(6cd81853-7b75-e911-a97a-000d3a34a1bd)

--changesetresponse_0c1567a5-ad0d-48fa-b81d-e6db05cad01c
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 2

HTTP/1.1 204 No Content
OData-Version: 4.0
Location: [Organization URI]/api/data/v9.2/contacts(6ed81853-7b75-e911-a97a-000d3a34a1bd)
OData-EntityId: [Organization URI]/api/data/v9.2/contacts(6ed81853-7b75-e911-a97a-000d3a34a1bd)

--changesetresponse_0c1567a5-ad0d-48fa-b81d-e6db05cad01c
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-ID: 3

HTTP/1.1 204 No Content
OData-Version: 4.0
Location: [Organization URI]/api/data/v9.2/accounts(6cd81853-7b75-e911-a97a-000d3a34a1bd)
OData-EntityId: [Organization URI]/api/data/v9.2/accounts(6cd81853-7b75-e911-a97a-000d3a34a1bd)

--changesetresponse_0c1567a5-ad0d-48fa-b81d-e6db05cad01c--
--batchresponse_9595d3ae-48f6-414f-a3aa-a3a33559859e--

Nota

Al hacer referencia a un Content-ID antes de que se haya declarado en el cuerpo de la solicitud se devolverá la solicitud errónea HTTP 400 del error.

El ejemplo siguiente muestra un cuerpo de la solicitud que puede producir este error.

Cuerpo de la solicitud

--batch_AAA123
Content-Type: multipart/mixed; boundary=changeset_BBB456

--changeset_BBB456
Content-Type: application/http
Content-Transfer-Encoding:binary
Content-ID: 2

POST [Organization URI]/api/data/v9.2/phonecalls HTTP/1.1
Content-Type: application/json;type=entry

{
    "phonenumber":"911",
    "regardingobjectid_account_phonecall@odata.bind" : "$1"
}

--changeset_BBB456
Content-Type: application/http
Content-Transfer-Encoding:binary
Content-ID: 1

POST [Organization URI]/api/data/v9.2/accounts HTTP/1.1
Content-Type: application/json;type=entry

{
    "name":"QQQQ",
    "revenue": 1.50
}

--changeset_BBB456--
--batch_AAA123--

Respuesta:

HTTP 400 Bad Request
Content-ID Reference: '$1' does not exist in the batch context.

Control de errores

Cuando ocurre un error para una solicitud dentro de un lote, el error de esa solicitud se devuelve para la solicitud de lote y las solicitudes adicionales no se procesan.

Puede usar el encabezado de solicitud Prefer: odata.continue-on-error para especificar que se procesen solicitudes adicionales cuando se produzcan errores. La solicitud por lotes devuelve 200 OK y los errores de respuesta individuales se devuelven en el cuerpo de la respuesta del lote.

Más información: Especificación OData: 8.2.8.3 Preference odata.continue-on-error

Ejemplo

El siguiente ejemplo intenta crear tres registros de tareas asociados con una cuenta con accountid igual a 00000000-0000-0000-0000-000000000001, pero la longitud de la propiedad subject para la primera tarea es demasiado larga.

Solicitud:

POST [Organization Uri]/api/data/v9.2/$batch HTTP/1.1
OData-MaxVersion: 4.0
OData-Version: 4.0
If-None-Match: null
Accept: application/json
Content-Type: multipart/mixed; boundary="batch_431faf5a-f979-4ee6-a374-d242f8962d41"
Content-Length: 1335

--batch_431faf5a-f979-4ee6-a374-d242f8962d41
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-Length: 436

POST /api/data/v9.2/tasks HTTP/1.1
Content-Type: application/json; type=entry

{
  "subject": "Subject is too long xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "regardingobjectid_account_task@odata.bind": "accounts(00000000-0000-0000-0000-000000000001)"
}
--batch_431faf5a-f979-4ee6-a374-d242f8962d41
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-Length: 250

POST /api/data/v9.2/tasks HTTP/1.1
Content-Type: application/json; type=entry

{
  "subject": "Task 2 in batch",
  "regardingobjectid_account_task@odata.bind": "accounts(00000000-0000-0000-0000-000000000001)"
}
--batch_431faf5a-f979-4ee6-a374-d242f8962d41
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-Length: 250

POST /api/data/v9.2/tasks HTTP/1.1
Content-Type: application/json; type=entry

{
  "subject": "Task 3 in batch",
  "regardingobjectid_account_task@odata.bind": "accounts(00000000-0000-0000-0000-000000000001)"
}
--batch_431faf5a-f979-4ee6-a374-d242f8962d41--

Sin configurar el encabezado de solicitud Prefer: odata.continue-on-error, el lote falla en la primera solicitud del lote. El error por lotes representa el error de la primera solicitud fallida.

Respuesta:

HTTP/1.1 400 BadRequest
OData-Version: 4.0

--batchresponse_156da4b8-cd2c-4862-a911-4aaab97c001a
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 400 Bad Request
REQ_ID: 5ecd1cb3-1730-4ffc-909c-d44c22270026
Content-Type: application/json; odata.metadata=minimal
OData-Version: 4.0

{"error":{"code":"0x80044331","message":"A validation error occurred.  The length of the 'subject' attribute of the 'task' entity exceeded the maximum allowed length of '200'."}}
--batchresponse_156da4b8-cd2c-4862-a911-4aaab97c001a--

Cuando el encabezado de solicitud Prefer: odata.continue-on-error se aplica a la solicitud por lotes, esta se realiza correctamente con un estado de 200 OK y el error de la primera solicitud se devuelve como parte del cuerpo.

Solicitud:

POST [Organization Uri]/api/data/v9.2/$batch HTTP/1.1
Prefer: odata.continue-on-error
OData-MaxVersion: 4.0
OData-Version: 4.0
If-None-Match: null
Accept: application/json
Content-Type: multipart/mixed; boundary="batch_662d4610-7f12-4895-ac4a-3fdf77cc10a1"
Content-Length: 1338

--batch_662d4610-7f12-4895-ac4a-3fdf77cc10a1
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-Length: 439

POST /api/data/v9.2/tasks HTTP/1.1
Content-Type: application/json; type=entry

{
  "subject": "Subject is too long xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
  "regardingobjectid_account_task@odata.bind": "accounts(00000000-0000-0000-0000-000000000001)"
}
--batch_662d4610-7f12-4895-ac4a-3fdf77cc10a1
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-Length: 250

POST /api/data/v9.2/tasks HTTP/1.1
Content-Type: application/json; type=entry

{
  "subject": "Task 2 in batch",
  "regardingobjectid_account_task@odata.bind": "accounts(00000000-0000-0000-0000-000000000001)"
}
--batch_662d4610-7f12-4895-ac4a-3fdf77cc10a1
Content-Type: application/http
Content-Transfer-Encoding: binary
Content-Length: 250

POST /api/data/v9.2/tasks HTTP/1.1
Content-Type: application/json; type=entry

{
  "subject": "Task 3 in batch",
  "regardingobjectid_account_task@odata.bind": "accounts(00000000-0000-0000-0000-000000000001)"
}
--batch_662d4610-7f12-4895-ac4a-3fdf77cc10a1--

Respuesta:

HTTP/1.1 200 OK
OData-Version: 4.0

--batchresponse_f44bd09d-573f-4a30-bca0-2e500ee7e139
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 400 Bad Request
REQ_ID: de4c5227-4a28-4ebd-8ced-3392ece1697b
Content-Type: application/json; odata.metadata=minimal
OData-Version: 4.0

{"error":{"code":"0x80044331","message":"A validation error occurred.  The length of the 'subject' attribute of the 'task' entity exceeded the maximum allowed length of '200'."}}
--batchresponse_f44bd09d-573f-4a30-bca0-2e500ee7e139
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 204 No Content
OData-Version: 4.0
Location: [Organization Uri]/api/data/v9.2/tasks(aed2ae8b-3c94-ed11-aad1-000d3a9933c9)
OData-EntityId: [Organization Uri]/api/data/v9.2/tasks(aed2ae8b-3c94-ed11-aad1-000d3a9933c9)


--batchresponse_f44bd09d-573f-4a30-bca0-2e500ee7e139
Content-Type: application/http
Content-Transfer-Encoding: binary

HTTP/1.1 204 No Content
OData-Version: 4.0
Location: [Organization Uri]/api/data/v9.2/tasks(b181a991-3c94-ed11-aad1-000d3a9933c9)
OData-EntityId: [Organization Uri]/api/data/v9.2/tasks(b181a991-3c94-ed11-aad1-000d3a9933c9)


--batchresponse_f44bd09d-573f-4a30-bca0-2e500ee7e139--

Métodos auxiliares de .NET

La biblioteca de clases WebAPIService (C#) es un proyecto de biblioteca de clases auxiliares de muestra que se usa para muestras de API web escritas en .NET. Demuestra una forma en que se pueden reutilizar los patrones comunes que se usan con la API web.

Nota

Esta biblioteca de muestras es una ayuda que utilizan todos los ejemplos de API web de C# de Dataverse, pero no es un SDK. Se prueba solo para confirmar que las muestras que lo usan se ejecutan correctamente. Este código de muestra se proporciona 'tal cual' sin garantía de reutilización.

Esta biblioteca incluye clases para crear solicitudes por lotes y procesar respuestas. Por ejemplo, se usaron variaciones en el siguiente código para generar muchos de los ejemplos de solicitud y respuesta HTTP en este artículo.

using PowerApps.Samples;
using PowerApps.Samples.Batch;

static async Task Main()
{
    Config config = App.InitializeApp();

    var service = new Service(config);

    JObject account = new()
    {
        {"name","test account" }
    };

    EntityReference accountRef = await service.Create("accounts", account);

    List<HttpRequestMessage> createRequests = new() {
        new CreateRequest("tasks",new JObject(){
            {"subject","Task 2 in batch" },
            {"regardingobjectid_account_task@odata.bind", accountRef.Path }
        }),
        new CreateRequest("tasks",new JObject(){
            {"subject","Task 2 in batch" },
            {"regardingobjectid_account_task@odata.bind", accountRef.Path }
        }),
        new CreateRequest("tasks",new JObject(){
            {"subject","Task 3 in batch" },
            {"regardingobjectid_account_task@odata.bind", accountRef.Path }
        })
    };

    BatchRequest batchRequest = new(service.BaseAddress)
    {
        Requests = createRequests,
        ContinueOnError = true
    };

    var batchResponse = await service.SendAsync<BatchResponse>(batchRequest);

    batchResponse.HttpResponseMessages.ForEach(response => {

        string path = response.As<CreateResponse>().EntityReference.Path;
        Console.WriteLine($"Task created at: {path}");
        
    });
}

output

Task created at: tasks(6743adfa-4a94-ed11-aad1-000d3a9933c9)
Task created at: tasks(6843adfa-4a94-ed11-aad1-000d3a9933c9)
Task created at: tasks(6943adfa-4a94-ed11-aad1-000d3a9933c9)

Dentro de esta biblioteca, hay algunos métodos que pueden resultarle útiles en su código .NET.

Más información:

Ejemplo de .NET HttpRequestMessage a HttpMessageContent

En .NET, debe enviar solicitudes en lote como MultipartContent, que es una colección de HttpContent. HttpMessageContent hereda de HttpContent. La biblioteca de clases WebAPIService (C#) clase BatchRequest utiliza el siguiente método estático privado ToMessageContent para convertir HttpRequestMessage a HttpMessageContent que se pueden agregar a MultipartContent.

/// <summary>
/// Converts a HttpRequestMessage to HttpMessageContent
/// </summary>
/// <param name="request">The HttpRequestMessage to convert.</param>
/// <returns>HttpMessageContent with the correct headers.</returns>
private HttpMessageContent ToMessageContent(HttpRequestMessage request)
{

    //Relative URI is not allowed with MultipartContent
    request.RequestUri = new Uri(
        baseUri: ServiceBaseAddress,
        relativeUri: request.RequestUri.ToString());

    if (request.Content != null)
    {
        if (request.Content.Headers.Contains("Content-Type"))
        {
            request.Content.Headers.Remove("Content-Type");
        }
        request.Content.Headers.Add("Content-Type", "application/json;type=entry");
    }

    HttpMessageContent messageContent = new(request);

    if (messageContent.Headers.Contains("Content-Type"))
    {
        messageContent.Headers.Remove("Content-Type");
    }
    messageContent.Headers.Add("Content-Type", "application/http");
    messageContent.Headers.Add("Content-Transfer-Encoding", "binary");

    return messageContent;

}

Ejemplo de respuesta en lote del analizador de .NET

La biblioteca de clases WebAPIService (C#) la clase BatchResponse utiliza el siguiente método estático privado ParseMultipartContent para analizar el cuerpo de una respuesta en lote en un List de HttpResponseMessage que se pueden procesar como respuestas individuales.

/// <summary>
/// Processes the Multi-part content returned from the batch into a list of responses.
/// </summary>
/// <param name="content">The Content of the response.</param>
/// <returns></returns>
private static async Task<List<HttpResponseMessage>> ParseMultipartContent(HttpContent content)
{
   MultipartMemoryStreamProvider batchResponseContent = await content.ReadAsMultipartAsync();

   List<HttpResponseMessage> responses = new();

   if (batchResponseContent?.Contents != null)
   {
         batchResponseContent.Contents.ToList().ForEach(async httpContent =>
         {

            //This is true for changesets
            if (httpContent.IsMimeMultipartContent())
            {
               //Recursive call
               responses.AddRange(await ParseMultipartContent(httpContent));
            }

            //This is for individual responses outside of a change set.
            else
            {
               //Must change Content-Type for ReadAsHttpResponseMessageAsync method to work.
               httpContent.Headers.Remove("Content-Type");
               httpContent.Headers.Add("Content-Type", "application/http;msgtype=response");

               HttpResponseMessage httpResponseMessage = await httpContent.ReadAsHttpResponseMessageAsync();

               if (httpResponseMessage != null)
               {
                     responses.Add(httpResponseMessage);
               }
            }
         });
   }

   return responses;
}

Consulte también

Realizar operaciones mediante la API web

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).