Lesen und Schreiben von Daten mit GraphQL in Fabric Apps

Fabric Apps bietet einen typsicheren GraphQL-Client, mit dem Sie Erstellungs-, Lese-, Aktualisierungs- und Löschvorgänge ausführen können, ohne unformatierte Abfragen zu schreiben. Der Client generiert GraphQL automatisch aus Ihren Methodenaufrufen und gibt typierte Entitäten basierend auf Ihren Datenmodelldefinitionen zurück.

Voraussetzungen

  • Ein Fabric-Apps-Projekt mit definierten Datenmodellen. Siehe Definieren von Datenmodellen.
  • Die Back-End-Dienste, die lokal ausgeführt oder für Fabric bereitgestellt werden.

Initialisieren des Clients

Instanziieren Sie RayfinClient mit Ihrer Backend-URL, dem veröffentlichbaren Schlüssel und dem Schematyp:

import { RayfinClient } from '@microsoft/rayfin-client';
import type { Note } from '../rayfin/data/Note';
import type { Notebook } from '../rayfin/data/Notebook';

type AppSchema = { 
  Note: Note;
  Notebook: Notebook;
};

const client = new RayfinClient<AppSchema>({
  baseUrl: import.meta.env.VITE_RAYFIN_API_URL ?? 'http://localhost:5168',
  publishableKey: 'pk-your-project-key',
});

Das generische Typargument ermöglicht TypeScript die Bereitstellung von AutoVervollständigen und Typüberprüfung für alle Datenvorgänge.

Daten lesen

Zugreifen auf Entitätssammlungen über client.data.<EntityName>. Die Fluent-API stellt Methoden zum Abfragen, Filtern, Sortieren und Paginieren bereit.

Alle Datensätze abrufen

const notes = await client.data.Note.select([
  'id',
  'title',
  'content',
  'createdAt',
  'isPinned',
]).execute();

Einen einzelnen Datensatz anhand des Primärschlüssels abrufen

const note = await client.data.Note.findByPk('00000000-0000-0000-0000-000000000000');

Dadurch wird die vollständige Entität zurückgegeben, oder null wenn kein Datensatz mit dieser ID vorhanden ist.

Datensätze filtern

Verwenden Sie die Methode where(), um Ergebnisse zu filtern:

const pinnedNotes = await client.data.Note.select([
  'id',
  'title',
  'isPinned',
])
  .where({ isPinned: { eq: true } })
  .execute();

Filteroperatoren

Operator Description Example
eq Gleich { status: { eq: 'active' } }
ne Ungleich { status: { ne: 'archived' } }
gt Größer als { age: { gt: 18 } }
gte Größer als oder gleich { age: { gte: 21 } }
lt Kleiner als { price: { lt: 100 } }
lte Kleiner oder gleich { price: { lte: 50 } }
contains Enthält Teilzeichenfolge { title: { contains: 'draft' } }

Ergebnisse sortieren

Verwenden Sie orderBy(), um Abfrageergebnisse zu sortieren:

const notes = await client.data.Note.select([
  'id',
  'title',
  'createdAt',
])
  .orderBy({ createdAt: 'desc' })
  .execute();

Sortieren nach mehreren Spalten:

const notes = await client.data.Note.select([
  'id',
  'title',
  'isPinned',
  'createdAt',
])
  .orderBy({ isPinned: 'desc' })
  .orderBy({ createdAt: 'desc' })
  .execute();

Wenn Sie Beziehungen mit den Dekoratoren @one() und @many() definieren, können Sie Felder verknüpfter Entitäten in dieselbe Abfrage einbeziehen:

const notes = await client.data.Note.select([
  'id',
  'title',
  'content',
  'notebook.id',
  'notebook.name',
  'notebook.color',
])
  .execute();

Jede Notiz enthält die zugehörigen Notizbuchdaten, ohne dass eine separate Abfrage erforderlich ist.

Paginierung großer Ergebnismengen

Verwenden Sie cursorbasierte Paginierung für große Listen:

const page = await client.data.Note.select([
  'id',
  'title',
  'createdAt',
])
  .orderBy({ createdAt: 'desc' })
  .first(25)
  .executePaginated();

console.log('Items:', page.items);
console.log('Has next page:', page.hasNextPage);
console.log('End cursor:', page.endCursor);

Rufen Sie die nächste Seite mit dem Cursor ab:

if (page.hasNextPage) {
  const nextPage = await client.data.Note.select([
    'id',
    'title',
    'createdAt',
  ])
    .orderBy({ createdAt: 'desc' })
    .first(25)
    .after(page.endCursor)
    .executePaginated();
}

Hinweis

Die totalCount Eigenschaft wird für den PagedResult Typ angezeigt, wird aber nicht vom Back-End aufgefüllt. Verwenden Sie items.length, um die Ergebnisse auf der aktuellen Seite zu zählen.

Datensätze erstellen

Verwenden Sie die create() Methode, um neue Datensätze einzufügen:

const newNote = await client.data.Note.create({
  title: 'Meeting notes',
  content: 'Discussion points from the team sync',
  isPinned: false,
  isArchived: false,
  createdAt: new Date(),
  updatedAt: new Date(),
  user_id: 'user-123',
});

Die Methode gibt die erstellte Entität mit allen aufgefüllten Feldern zurück, einschließlich der automatisch generierten id.

Erstellen von Datensätzen mit Beziehungen

Übergeben Sie beim Erstellen von Entitäten mit Beziehungen entweder das vollständige verknüpfte Objekt oder ein Objekt mit nur dem Primärschlüssel:

// Option 1: Pass just the ID
const note = await client.data.Note.create({
  title: 'Weekly summary',
  content: 'Summary of this week',
  notebook: { id: 'notebook-456' },
  isPinned: false,
  isArchived: false,
  createdAt: new Date(),
  updatedAt: new Date(),
});

// Option 2: Pass the full object
const notebook = await client.data.Notebook.findByPk('notebook-456');
const note = await client.data.Note.create({
  title: 'Weekly summary',
  content: 'Summary of this week',
  notebook: notebook,
  isPinned: false,
  isArchived: false,
  createdAt: new Date(),
  updatedAt: new Date(),
});

Beide Formen erzeugen dasselbe Ergebnis. Verwenden Sie das erste Formular, wenn Sie bereits die ID der zugehörigen Entität kennen und einen zusätzlichen Abruf vermeiden möchten.

Datensätze aktualisieren

Verwenden Sie die update() Methode, um vorhandene Datensätze zu ändern. Übergeben Sie ein Filterobjekt und ein Objekt, das die zu aktualisierenden Felder enthält:

await client.data.Note.update(
  { id: 'note-123' },
  {
    title: 'Updated title',
    updatedAt: new Date(),
  }
);

Aktualisieren von Beziehungen

Um eine Beziehung zu ändern, übergeben Sie die neue verknüpfte Entität oder nur ihre ID:

// Move a note to a different notebook
await client.data.Note.update(
  { id: 'note-123' },
  { notebook: { id: 'new-notebook-789' } }
);

Datensätze löschen

Verwenden Sie die delete() Methode, um Datensätze zu entfernen, die mit einem Filter übereinstimmen:

await client.data.Note.delete({ id: 'note-123' });

Die Methode wird aufgelöst, wenn das Back-End das Löschen bestätigt. Wenn keine Datensätze mit dem Filter übereinstimmen, ist die Methode weiterhin erfolgreich.

Behandeln der Authentifizierung

Wenn die Authentifizierung aktiviert ist, melden Sie sich vor dem Ausführen von Datenvorgängen an:

await client.auth.signIn({ email, password });

// All subsequent data calls include authentication context
const notes = await client.data.Note.select(['id', 'title']).execute();

Der Client fügt die Authentifizierungssitzung automatisch an alle Daten-API-Aufrufe an. Sie müssen Token nicht manuell übergeben.

Bewährte Methoden

  • Wählen Sie nur erforderliche Felder aus – Rufen Sie nur die Felder ab, die Sie verwenden, um die Nutzlastgröße zu verringern und die Leistung zu verbessern.
  • Verwenden Sie die Paginierung für große Listen – Vermeiden Sie das Gleichzeitige Abrufen von Tausenden von Datensätzen mithilfe first() und executePaginated().
  • Batchbeziehungsabfragen – Fügen Sie verwandte Entitätsfelder in dieselbe Abfrage ein, anstatt separate Anforderungen auszuführen.
  • Häufig verwendete Daten zwischenspeichern – Speichern Sie statische Referenzdaten im Arbeitsspeicher, um API-Aufrufe zu reduzieren.

Aktuelle Einschränkungen

  • Die count() Methode ist auf dem Fluent-Client nicht verfügbar. Wählen Sie die minimalen Felder aus und verwenden Sie stattdessen results.length.
  • M:n-Beziehungen werden nicht unterstützt. Verwenden Sie eine explizite Verknüpfungsentität mit zwei @one() Navigationsdekortoren.
  • Die Eigenschaft totalCount bei PagedResult wird nicht vom Backend gesetzt.