Führen Sie ExecuteMultiple in Batches und Changesets aus TypeScript mit Dataverse-ify Version 2 aus

Mein kostenloser Tutorial-Kurs zum Schreiben von Dataverse-Webressourcen ist jetzt seit über einem Jahr verfügbar und es haben sich über 1000 Personen angemeldet! Der Kurs verwendet Version 1 von dataverse-ifyund natürlich habe ich in dieser Zeit an Version 2 gearbeitet, die derzeit als Betaversion verfügbar ist.

Was ist Dataverse-ify?

Dataverse-ify soll den Aufruf der Dataverse WebAPI vereinfachen Typoskript in modellgesteuerten Apps, Single Page Applications (SPAs) und Integrationstests, die in VSCode/Node ausgeführt werden. Es verwendet eine kleine Menge an Metadaten, die mit generiert werden dataverse-gen und eine Reihe von früh gebundenen Typen, um die Interaktion mit Dataverse-Tabellen und -Spalten mithilfe einer ähnlichen API zu vereinfachen, die Sie möglicherweise verwenden, wenn Sie die verwendet haben IOrganizationService innerhalb von C#.

Sie können die neue Version verwenden, indem Sie hinzufügen @2 am Ende der Knotenmodule:

Zum Beispiel:

npx dataverse-auth@2
npx dataverse-gen@2
npm install dataverse-ify@2

Bald werde ich das Beta-Tag entfernen und veröffentlichen, damit es standardmäßig installiert wird. Es gibt ein paar bahnbrechende Änderungen, die in der Readme-Datei zum Upgrade aufgeführt sind, aber ich werde weitere Beispiele veröffentlichen, einschließlich einer Einzelseitenanwendung, die verwendet dataverse-ify auch wo die Xrm.WebApi ist nicht verfügbar.

Ich wollte Ihnen einen Blick auf eine der Funktionen geben, auf die ich mich in Version 2 wirklich freue – die Unterstützung ExecuteMultiple mit Batch- und Change-Set-Unterstützung. Mit einem Stapel können Sie mehrere Anforderungen in einer einzigen Anforderung senden, und mit Änderungssets können Sie mehrere Anforderungen senden, die als Transaktion ausgeführt werden. Dies kann Ihrem clientseitigen Code einen Leistungsschub verleihen und es einfacher machen, einen einzelnen Änderungssatz durchzuführen, bei dem, wenn eine Anforderung fehlschlägt, alle fehlschlagen. Benutzerdefinierte API-Anforderungen können sogar eingepackt werden executeMultiple!

Stellen Sie sich vor, Sie haben eine Befehlsleistenschaltfläche, die eine JavaScript-Funktion aus einem Raster aufruft, das eine Aktualisierung an einer Spalte aller ausgewählten Datensätze vornehmen muss, und dann warten, bis ein ausgelöster Flow ausgeführt wird, was durch das Zurücksetzen der aktualisierten Spalte angezeigt wird . Die Aktualisierungen können in einem ExecuteMultiple-Batch zusammengefasst werden, anstatt durch viele Aktualisierungsanforderungen vorgenommen zu werden.

Erstellen Sie die Funktion der obersten Ebene

Wenn eine Befehlsleiste eine JavaScript-Funktion aufruft, kann sie ein Promise zurückgeben, wenn asynchrone Arbeit ausgeführt wird. In unserem Fall möchten wir nicht, dass die modellgesteuerte App wartet, bis unsere Flows ausgeführt werden, damit wir sie verwenden können Promise.resolve auf eine interne Funktion, um eine lang andauernde Aufgabe zu “feuern und zu vergessen”:

static async CreateProjectReportTrigger(entityIds: string[]): Promise {
  // Fire and forget the internal command so it does not cause a ribbon action timeout
  Promise.resolve(ProjectRibbon.CreateProjectReportTriggerInternal(entityIds));
}

Erstellen Sie die Internal-Funktion und initialisieren Sie den Metadaten-Cache

Innerhalb der internen Funktion müssen wir zuerst unsere Metadaten festlegen, die mit erstellt wurden dataverse-gen – dies bietet dataverse-ify Mit einigen der Informationen muss es die Datentypen von Spalten ausarbeiten, die nicht in der vorhanden sind WebApi Antworten. Wir erstellen auch einen zufälligen Wert, um die Spalte zu aktualisieren, die den Fluss auslöst:

setMetadataCache(metadataCache);jj
const requestCount = entityIds.length;
const trigger = "trigger" + Math.random().toString();

Führen Sie das Update mit executeMultiple durch (dies ist nicht C#, denken Sie daran, es ist TypeScript!)

Hier passiert die Magie – wir können eine Reihe von erstellen UpdateRequest Objekte mit der entitiyIds bereitgestellt, um von der Befehlsleiste aus zu funktionieren:

// Trigger the flow for each selected project (using a batch)
const updates = entityIds.map((id) => {
  return {
    logicalName: "Update",
    target: {
      logicalName: dev1_projectMetadata.logicalName,
      dev1_projectid: id,
      dev1_reportgenerationstatus: trigger,
    } as dev1_Project,
  } as UpdateRequest;
});
const serviceClient = new XrmContextDataverseClient(Xrm.WebApi);
await serviceClient.executeMultiple(updates);

Sie können sehen, dass das Updates-Array einfach übergeben wird executeMultiple die sie dann in a bündeln $batch Anfrage. Wenn Sie möchten, können Sie die Aktualisierungen innerhalb einer Transaktion ausführen, indem Sie den Stapel einfach in ein Array einschließen:

await serviceClient.executeMultiple([updates]);

Dieses Array könnte tatsächlich mehrere Änderungssätze enthalten, von denen jeder unabhängig innerhalb einer Transaktion ausgeführt würde.

Die resultierende Funktion wäre also:

static async CreateProjectReportTriggerInternal(entityIds: string[]): Promise {
  // Update a column on the selected records, to trigger a flow
  try {
    setMetadataCache(metadataCache);
    const requestCount = entityIds.length;
    const trigger = "trigger" + Math.random().toString();
    // Trigger the flow for each selected project (using a batch)
    const updates = entityIds.map((id) => {
      return {
        logicalName: "Update",
        target: {
          logicalName: dev1_projectMetadata.logicalName,
          dev1_projectid: id,
          dev1_reportgenerationstatus: trigger,
        } as dev1_Project,
      } as UpdateRequest;
    });
    const serviceClient = new XrmContextDataverseClient(Xrm.WebApi);
    await serviceClient.executeMultiple(updates);
    // Monitor the result
    const query = `
      
      
      
          
      
      
  `;
    let complete = false;
    do {
      const inProgressQuery = await serviceClient.retrieveMultiple(query, { returnRawEntities: true });
      complete = inProgressQuery.entities.length === 0;
      if (!complete) {
        const inProgressCount = inProgressQuery.entities[0]["count_items"] as number;
        complete = inProgressCount === 0;
        // Report status
        Xrm.Utility.showProgressIndicator(`Generating Reports ${requestCount - inProgressCount}/${requestCount}`);
        await ProjectRibbon.sleepTimeout(2000);
      }
    } while (!complete);
    Xrm.Utility.closeProgressIndicator();
  } catch (e) {
    Xrm.Utility.closeProgressIndicator();
    Xrm.Navigation.openErrorDialog({ message: "Could not generate reports", details: JSON.stringify(e) });
  }
}

static sleepTimeout(ms: number): Promise {
  return new Promise((resolve) => setTimeout(resolve, ms));
}

Dieser Code fügt die Abfrage für die Anzahl der Datensätze hinzu, für die der Flow noch ausgeführt und zurückgesetzt werden muss dev1_reportgenerationstatus -Attribut, das angibt, dass es abgeschlossen ist oder einen Fehler meldet.

Die Batch-Anfrage würde etwa so aussehen:

--batch_1665710705198
Content-Type: application/http
Content-Transfer-Encoding: binary

PATCH /api/data/v9.0/dev1_projects(2361e495-1419-ed11-b83e-000d3a2ae2ee) HTTP/1.1
Content-Type: application/json

{"dev1_reportgenerationstatus":"trigger0.39324146578062336","@odata.type":"Microsoft.Dynamics.CRM.dev1_project"}
--batch_1665710705198
Content-Type: application/http

PATCH /api/data/v9.0/dev1_projects(e8184b63-1823-ed11-b83d-000d3a39d9b6) HTTP/1.1
Content-Type: application/json

{"dev1_reportgenerationstatus":"trigger0.39324146578062336","@odata.type":"Microsoft.Dynamics.CRM.dev1_project"}

--batch_1665710705198--

Der Code kann offensichtlich verbessert werden, indem ein Timeout hinzugefügt und Fehler besser gemeldet werden – aber dies zeigt die allgemeine Idee der Verwendung executeMultiple verwenden dataverse-ify Version 2.

Es gibt viele weitere Verbesserungen in Version 2 – wenn Sie also Version 1 verwendet haben, probieren Sie Version 2 bitte aus, während sie sich in der Beta-Phase befindet, und melden Sie alle Probleme innerhalb von GitHub.

In meinem nächsten Beitrag zu Version 2 zeige ich Ihnen, wie Sie eine benutzerdefinierte API mithilfe eines Stapels und eines Änderungssatzes aufrufen. Wenn Sie vorher einen Blick darauf werfen möchten, werfen Sie einen Blick auf die Tests für Version 2 – sie geben viele Beispiele für die Verwendung.

@ScottDurow

.

Author: admin

Leave a Reply

Your email address will not be published. Required fields are marked *