Compartir a través de


Ejecución de operaciones por lotes mediante la API web

Puede agrupar varias operaciones en una única solicitud HTTP mediante una operación por lotes. Dataverse realiza estas operaciones secuencialmente en el orden especificado. El orden de las respuestas coincide con el orden de las solicitudes en la operación por lotes.

El formato para enviar $batch solicitudes se define en 11.7 Solicitudes por lotes en la especificación de OData. En este artículo se resumen los requisitos de especificación y se proporciona información y ejemplos específicos de Dataverse.

Cuándo usar solicitudes por lotes

Las solicitudes por lotes proporcionan dos funcionalidades que puede usar juntas:

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

    • Las 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. Para obtener más información, consulte Ejecución de varias solicitudes mediante el SDK para .NET.
  • Puede agrupar solicitudes de operaciones para que se incluyan como una sola transacción mediante conjuntos de cambios.

    • Es posible que quiera crear, actualizar o eliminar un conjunto de registros relacionados de una manera que garantice que todas las operaciones tengan éxito o fracasen como un grupo.
    • Las solicitudes de Web API $batch mediante lotes de cambios equivalen al mensaje ExecuteTransaction disponible en el SDK para .NET. Para obtener más información, vea Ejecutar mensajes en una sola transacción de base de datos.

    Nota

    Puede crear entidades asociadas en una sola operación más fácilmente que mediante una solicitud por lotes. Para obtener más información, consulte Creación de filas de tabla relacionadas en una sola operación.

A veces, las personas usan solicitudes por lotes para enviar GET solicitudes cuando la longitud de la dirección URL puede superar la longitud máxima permitida de la dirección URL. Al usar solicitudes por lotes, se incluye la dirección URL de la solicitud en el cuerpo del mensaje donde se permite una dirección URL de hasta 64 KB (65 536 caracteres). El envío de consultas complejas mediante FetchXml puede dar lugar a direcciones URL largas. Para obtener más información, consulte Uso de FetchXML dentro de una solicitud por lotes.

En comparación con otras operaciones que puede realizar mediante 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 POST solicitud que contiene el lote debe tener un encabezado Content-Type con un valor establecido multipart/mixed con un boundary para que incluya el identificador del lote mediante 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 del lote debe ir precedido por el identificador de lote con un Content-Type y un encabezado Content-Transfer-Encoding, como se muestra en el ejemplo siguiente.

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

Importante

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

Debe incluir cualquier otro encabezado HTTP para cada elemento del conjunto para gestionar el comportamiento de la solicitud. Los encabezados aplicados a la $batch operación no se aplican 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 por lotes debe contener un indicador de terminación, como se muestra en el ejemplo siguiente:

--batch_<unique identifier>--

Nota

El protocolo HTTP requiere que todas las terminaciones de línea en las cargas 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 usar CRLF, puede agregar dos finales de línea que no sean CRLF al final de la carga de la solicitud para evitar 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 se ejecuta correctamente, la respuesta del lote devuelve el estado HTTP 200 OK. Cada elemento de la respuesta está separado por un Guid valor de identificador único que no es el mismo que el valor de solicitud por lotes.

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

El final de la respuesta por lotes contiene un indicador de terminación, como se muestra en el ejemplo siguiente:

--batchresponse_<unique identifier>--

En el ejemplo siguiente se muestra 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(00aa00aa-bb11-cc22-dd33-44ee44ee44ee)
OData-EntityId: [Organization Uri]/api/data/v9.2/tasks(00aa00aa-bb11-cc22-dd33-44ee44ee44ee)


--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(11bb11bb-cc22-dd33-ee44-55ff55ff55ff)
OData-EntityId: [Organization Uri]/api/data/v9.2/tasks(11bb11bb-cc22-dd33-ee44-55ff55ff55ff)


--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(22cc22cc-dd33-ee44-ff55-66aa66aa66aa)
OData-EntityId: [Organization Uri]/api/data/v9.2/tasks(22cc22cc-dd33-ee44-ff55-66aa66aa66aa)


--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": "00aa00aa-bb11-cc22-dd33-44ee44ee44ee"
    },
    {
      "@odata.etag": "W/\"77180910\"",
      "subject": "Task 2 in batch",
      "activityid": "11bb11bb-cc22-dd33-ee44-55ff55ff55ff"
    },
    {
      "@odata.etag": "W/\"77180913\"",
      "subject": "Task 3 in batch",
      "activityid": "22cc22cc-dd33-ee44-ff55-66aa66aa66aa"
    }
  ]
}
--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 se produce un error en alguna de las operaciones, la solicitud por lotes revierte las operaciones completadas.

Nota

GET No se permiten solicitudes en conjuntos de cambios. Una GET operación no cambia los datos, por lo que no pertenece a un conjunto de cambios.

Al igual que una solicitud por lotes, los conjuntos de cambios deben tener un Content-Type encabezado con el valor configurado en multipart/mixed, con un boundary conjunto para incluir el identificador del conjunto de cambios mediante 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 tiene como , represents a variable that contains the URI for any entity created in that operation. For example, when you set the value of prefijo 1, you can refer to that entity by using $1' más adelante en el conjunto de cambios. Para más información, consulte 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 el valor accountid00000000-0000-0000-0000-000000000001.
  • Recupere las cuentas creadas mediante una GET solicitud 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(33dd33dd-ee44-ff55-aa66-77bb77bb77bb)
OData-EntityId: [Organization Uri]/api/data/v9.2/tasks(33dd33dd-ee44-ff55-aa66-77bb77bb77bb)


--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(44ee44ee-ff55-aa66-bb77-88cc88cc88cc)
OData-EntityId: [Organization Uri]/api/data/v9.2/tasks(44ee44ee-ff55-aa66-bb77-88cc88cc88cc)


--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(55ff55ff-aa66-bb77-cc88-99dd99dd99dd)
OData-EntityId: [Organization Uri]/api/data/v9.2/tasks(55ff55ff-aa66-bb77-cc88-99dd99dd99dd)


--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": "33dd33dd-ee44-ff55-aa66-77bb77bb77bb"
    },
    {
      "@odata.etag": "W/\"77181176\"",
      "subject": "Task 2 in batch",
      "activityid": "44ee44ee-ff55-aa66-bb77-88cc88cc88cc"
    },
    {
      "@odata.etag": "W/\"77181179\"",
      "subject": "Task 3 in batch",
      "activityid": "55ff55ff-aa66-bb77-cc88-99dd99dd99dd"
    }
  ]
}
--batchresponse_f27ef42d-51b0-4685-bac9-f468f844de2f--

Hacer referencia a URI en una operación

Dentro de los conjuntos de cambios, puede usar $parameter como $1, $2, etc. para hacer referencia a los URIs devueltos para las 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.

En esta sección se muestran varios ejemplos de cómo usar $parameter en el cuerpo de la solicitud de una operación por lotes para hacer referencia a los URI.

Hacer referencia a URI en el cuerpo de la solicitud

En el ejemplo siguiente se muestra cómo usar dos referencias de URI 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(66aa66aa-bb77-cc88-dd99-00ee00ee00ee)
OData-EntityId: [Organization URI]/api/data/v9.2/leads(66aa66aa-bb77-cc88-dd99-00ee00ee00ee)

--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(00aa00aa-bb11-cc22-dd33-44ee44ee44ee)
OData-EntityId: [Organization URI]/api/data/v9.2/contacts(00aa00aa-bb11-cc22-dd33-44ee44ee44ee)

--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(11bb11bb-cc22-dd33-ee44-55ff55ff55ff)
OData-EntityId: [Organization URI]/api/data/v9.2/accounts(11bb11bb-cc22-dd33-ee44-55ff55ff55ff)

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

Referenciar URI en la URL de la solicitud

En el ejemplo siguiente se muestra cómo hacer referencia a un URI mediante $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(22cc22cc-dd33-ee44-ff55-66aa66aa66aa)
OData-EntityId:[Organization URI]/api/data/v9.2/contacts(22cc22cc-dd33-ee44-ff55-66aa66aa66aa)


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

URI de referencia en URL y cuerpo de la solicitud mediante @odata.id

El ejemplo siguiente muestra cómo vincular un registro de entidad Contacto a un registro de entidad Cuenta. Se hace referencia al URI del registro de entidad Account como $1 y se hace referencia al URI del registro de entidad Contact 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(33dd33dd-ee44-ff55-aa66-77bb77bb77bb)
OData-EntityId:[Organization URI]/api/data/v9.2/accounts(33dd33dd-ee44-ff55-aa66-77bb77bb77bb)

--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(44ee44ee-ff55-aa66-bb77-88cc88cc88cc)
OData-EntityId:[Organization URI]/api/data/v9.2/contacts(44ee44ee-ff55-aa66-bb77-88cc88cc88cc)

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

Referenciar URI en propiedades URL y de navegación

En el ejemplo siguiente se muestra cómo usar el URI de la organización de un registro de contacto y vincularlo a un registro de cuenta mediante la primarycontactid propiedad de navegación con un solo valor. El URI del registro de la entidad Account se referencia como $1 y el URI del registro de la entidad Contact se 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(55ff55ff-aa66-bb77-cc88-99dd99dd99dd)
OData-EntityId: [Organization URI]/api/data/v9.2/accounts(55ff55ff-aa66-bb77-cc88-99dd99dd99dd)

--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(66aa66aa-bb77-cc88-dd99-00ee00ee00ee)
OData-EntityId: [Organization URI]/api/data/v9.2/contacts(66aa66aa-bb77-cc88-dd99-00ee00ee00ee)

--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(55ff55ff-aa66-bb77-cc88-99dd99dd99dd)
OData-EntityId: [Organization URI]/api/data/v9.2/accounts(55ff55ff-aa66-bb77-cc88-99dd99dd99dd)

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

Nota

Al hacer referencia a un Content-ID antes de que aparezca en el cuerpo de la solicitud, se devuelve el error HTTP 400 Solicitud incorrecta.

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 se produce un error para una solicitud dentro de un lote, la solicitud por lotes devuelve el error de esa solicitud y no procesa más solicitudes.

Si agrega el encabezado de Prefer: odata.continue-on-error solicitud, puede especificar que el servidor procesa más solicitudes cuando se producen errores. La solicitud por lotes devuelve 200 OKy los errores de respuesta individuales se incluyen en el cuerpo de la respuesta por lotes.

Más información: Especificación OData: 8.2.8.3 Preferencia 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 establecer 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--

Al agregar el Prefer: odata.continue-on-error encabezado de solicitud a la solicitud por lotes, la solicitud por lotes se completa correctamente con un estado de 200 OK y el error de la primera solicitud se devuelve como parte del contenido.

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(00aa00aa-bb11-cc22-dd33-44ee44ee44ee)
OData-EntityId: [Organization Uri]/api/data/v9.2/tasks(00aa00aa-bb11-cc22-dd33-44ee44ee44ee)


--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(11bb11bb-cc22-dd33-ee44-55ff55ff55ff)
OData-EntityId: [Organization Uri]/api/data/v9.2/tasks(11bb11bb-cc22-dd33-ee44-55ff55ff55ff)


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

Métodos auxiliares de .NET

La biblioteca de clases WebAPIService (C#) es un proyecto de biblioteca de clases auxiliar de ejemplo para ejemplos de API web escritos en .NET. Muestra una manera de reutilizar patrones comunes que se usan con la API web.

Nota

Esta biblioteca de ejemplo es un asistente que usan 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 ejemplo se proporciona "as-is" sin garantía para su reutilización.

Esta biblioteca incluye clases para crear solicitudes por lotes y procesar respuestas. Por ejemplo, se usaron variaciones en el código siguiente para generar muchos de los ejemplos de solicitud y respuesta HTTP de 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)

En esta biblioteca, es posible que encuentre algunos métodos útiles para el código de .NET.

Más información:

Ejemplo de .NET HttpRequestMessage a HttpMessageContent

En .NET, debe enviar solicitudes por lotes como MultipartContent, que es una colección de HttpContent. HttpMessageContent hereda de HttpContent. La biblioteca de clases WebAPIService (C#) BatchRequest utiliza el siguiente método estático ToMessageContent privado para convertir HttpRequestMessage a HttpMessageContent, que puede 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 usa el siguiente método estático ParseMultipartContent privado para analizar el cuerpo de una respuesta por lotes en una lista List de HttpResponseMessage que puedes 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