Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of mappen te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen om mappen te wijzigen.
Fabric Apps biedt een typeveilige GraphQL-client waarmee u bewerkingen voor maken, lezen, bijwerken en verwijderen kunt uitvoeren zonder onbewerkte query's te schrijven. De client genereert GraphQL automatisch vanuit uw methode-aanroepen en retourneert getypte entiteiten op basis van uw gegevensmodeldefinities.
Prerequisites
- Een Fabric Apps-project met gegevensmodellen gedefinieerd. Zie Gegevensmodellen definiëren.
- De back-endservices die lokaal worden uitgevoerd of geïmplementeerd in Fabric.
De client initialiseren
Instantieer RayfinClient met uw back-end-URL, publiceerbare sleutel en schematype:
import { RayfinClient } from '@microsoft/rayfin-client';
import type { UniversalAppSchema } from '@rayfin-app/shared';
const client = new RayfinClient<UniversalAppSchema>({
baseUrl: import.meta.env.VITE_RAYFIN_API_URL,
publishableKey: import.meta.env.VITE_RAYFIN_PUBLISHABLE_KEY,
});
Met het generieke typeargument kan TypeScript automatische aanvulling en typecontrole bieden voor alle gegevensbewerkingen.
Deze voorbeelden gaan ervan uit dat je Data hebt ingeschakeld en Note en Notebook hebt geregistreerd in de packages/data/src/index.ts en het gedeelde schemacontract van de Universal App. In een flat template importeer je je schematype in plaats daarvan vanuit rayfin/data/schema.ts. Zie Gegevensmodellen definiëren.
Gegevens lezen
Toegang tot entiteitsverzamelingen via client.data.<EntityName>. De fluent-API biedt methoden voor het uitvoeren van query's, filteren, sorteren en paginering.
Haal een pagina met records
execute() Geeft standaard slechts één pagina terug, met 100 records. Het geeft geen cursormetadata terug en haalt geen volgende pagina's op. Gebruik voorwaartse paginering voor lijsten die verder kunnen groeien dan één pagina.
const notes = await client.data.Note.select([
'id',
'title',
'content',
'createdAt',
'isPinned',
]).execute();
Eén record ophalen op basis van primaire sleutel
const note = await client.data.Note.findById('00000000-0000-0000-0000-000000000000');
findById() retourneert null als er geen record bestaat. De uitgebrachte implementatie selecteert alleen de primaire sleutel, dus ga er niet van uit dat andere entiteitsvelden zijn gevuld. Selecteer velden expliciet wanneer je hun waarden nodig hebt:
const notes = await client.data.Note.select(['id', 'title', 'content'])
.where({ id: { eq: '00000000-0000-0000-0000-000000000000' } })
.first(1)
.execute();
const note = notes[0] ?? null;
Records filteren
Gebruik de where() methode om resultaten te filteren:
const pinnedNotes = await client.data.Note.select([
'id',
'title',
'isPinned',
])
.where({ isPinned: { eq: true } })
.execute();
Filter-operators
| Operator | Beschrijving | Example |
|---|---|---|
eq |
Gelijk aan | { status: { eq: 'active' } } |
neq |
Niet gelijk aan | { status: { neq: 'archived' } } |
gt |
Groter dan | { age: { gt: 18 } } |
gte |
Groter dan of gelijk aan | { age: { gte: 21 } } |
lt |
Kleiner dan | { price: { lt: 100 } } |
lte |
Kleiner dan of gelijk aan | { price: { lte: 50 } } |
contains |
Bevat subtekenreeks | { title: { contains: 'draft' } } |
Resultaten sorteren
Gebruik orderBy() dit om queryresultaten te sorteren:
const notes = await client.data.Note.select([
'id',
'title',
'createdAt',
])
.orderBy({ createdAt: 'desc' })
.execute();
Sorteren op meerdere kolommen:
const notes = await client.data.Note.select([
'id',
'title',
'isPinned',
'createdAt',
])
.orderBy({ isPinned: 'desc' })
.orderBy({ createdAt: 'desc' })
.execute();
Navigeren in relaties
Wanneer u relaties met @one() en @many() decorators definieert, kunt u gerelateerde entiteitsvelden opnemen in dezelfde query:
const notes = await client.data.Note.select([
'id',
'title',
'content',
'notebook.id',
'notebook.name',
])
.execute();
Elke notitie bevat de bijbehorende notebookgegevens zonder dat er een afzonderlijke query nodig is.
Grote resultatensets pagineren
Op cursor gebaseerde paginering gebruiken voor grote lijsten:
const page = await client.data.Note.select([
'id',
'title',
'createdAt',
])
.orderBy({ createdAt: 'desc' })
.orderBy({ id: 'asc' })
.first(25)
.executePaginated();
console.log('Items:', page.items);
console.log('Has next page:', page.hasNextPage);
console.log('End cursor:', page.endCursor);
Haal de volgende pagina op met behulp van de cursor:
if (page.hasNextPage) {
if (!page.endCursor) {
throw new Error('The next page is missing its cursor.');
}
const nextPage = await client.data.Note.select([
'id',
'title',
'createdAt',
])
.orderBy({ createdAt: 'desc' })
.orderBy({ id: 'asc' })
.first(25)
.after(page.endCursor)
.executePaginated();
}
Opmerking
De backend vult de totalCount property niet op het PagedResult type. De page.items.length waarde telt alleen de huidige pagina, niet alle overeenkomende records.
Om elk overeenkomend record te verwerken, ga je verder tot hasNextPagefalse is. Houd selecties, filters en sorteervolgorde ongewijzigd tussen verzoeken.
let cursor: string | undefined;
let matchingRecords = 0;
while (true) {
let query = client.data.Note.select(['id'])
.where({ isArchived: { eq: false } })
.orderBy({ id: 'asc' })
.first(100);
if (cursor !== undefined) {
query = query.after(cursor);
}
const page = await query.executePaginated();
matchingRecords += page.items.length;
if (!page.hasNextPage) {
break;
}
if (!page.endCursor) {
throw new Error('The next page is missing its cursor.');
}
cursor = page.endCursor;
}
console.log('Records read across all pages:', matchingRecords);
Paging geeft geen snapshot over meerdere verzoeken heen. Gelijktijdige wijzigingen kunnen invloed hebben op de records die je leest en telt.
Gegevens aggregeren en groeperen
Gebruik aggregate() voor server-side totals en groupBy() voor samenvattingen per groep. De zelfstandige fluent-methode count() is niet beschikbaar, maar count wordt ondersteund binnen een aggregatiespecificatie.
Alle vijf de aggregatebewerkingen (sum, avg, min, , maxen count) vereisen een numeriek veld. Reken een UUID id of een tekstveld niet mee. Bijvoorbeeld, de volgende zoekopdracht gaat ervan uit dat er een geregistreerde Product-entiteit is met een verplicht numeriek stockQuantity-veld:
const totals = await client.data.Product.where({ isAvailable: { eq: true } })
.aggregate({
matchingProducts: { count: 'stockQuantity' },
totalStock: { sum: 'stockQuantity' },
averageStock: { avg: 'stockQuantity' },
lowestStock: { min: 'stockQuantity' },
highestStock: { max: 'stockQuantity' },
})
.execute();
console.log(totals[0].aggregations.matchingProducts);
count telt niet-nulwaarden van het opgegeven numerieke veld. Gebruik een vereiste numeriek veld om overeenkomende rijen te tellen. Als je entiteit geen geschikt veld heeft, tel dan de identificatoren over alle pagina's zoals eerder getoond, niet slechts op één pagina.
Voor gegroepeerde totalen:
const groups = await client.data.Product.groupBy(['status'])
.aggregate({
matchingProducts: { count: 'stockQuantity' },
totalStock: { sum: 'stockQuantity' },
})
.execute();
for (const row of groups) {
console.log(row.fields.status, row.aggregations.totalStock);
}
Aggregatieresultaten zijn arrays met fields en aggregations objecten. Een eindtotaal heeft één rij met een leeg fields object.
count geeft een number; de andere bewerkingen geven number | null terug bij lege of volledig null-invoer.
Pas aan where() vóór de aggregatie. Combineer aggregatie niet met rijselectie, ordening of bladeren door select(), orderBy(), first() of after().
Records maken
Gebruik de create() methode om nieuwe records in te voegen:
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',
});
De methode retourneert het aangemaakte record, inclusief de automatisch gegenereerde id. Gebruik een expliciete selected read wanneer je extra opgeslagen velden nodig hebt.
Records aanmaken met relaties
Wanneer u entiteiten met relaties maakt, geeft u het volledige gerelateerde object of een object door met alleen de primaire sleutel:
// Option 1: Pass just the ID
const note = await client.data.Note.create({
title: 'Weekly summary',
content: 'Summary of this week',
notebook: { id: '22222222-3333-4444-5555-666666666666' },
isPinned: false,
isArchived: false,
createdAt: new Date(),
updatedAt: new Date(),
});
// Option 2: Select the related fields you need before creating the note.
const notebooks = await client.data.Notebook.select(['id', 'name'])
.where({ id: { eq: '22222222-3333-4444-5555-666666666666' } })
.first(1)
.execute();
const notebook = notebooks[0];
if (!notebook) {
throw new Error('Notebook not found.');
}
const noteWithNotebook = await client.data.Note.create({
title: 'Weekly summary',
content: 'Summary of this week',
notebook,
isPinned: false,
isArchived: false,
createdAt: new Date(),
updatedAt: new Date(),
});
Beide vormen produceren hetzelfde resultaat. Gebruik het eerste formulier wanneer u de id van de gerelateerde entiteit al kent en een extra ophaaloptie wilt voorkomen.
De client gebruikt de primaire sleutel van het gerelateerde object om de relatie in te stellen. Het doorgeven van een object creëert het bijbehorende notitieboek niet en werkt het ook niet bij.
Records bijwerken
Gebruik de update() methode om bestaande records te wijzigen. Geef een filterobject en een object met de velden door die moeten worden bijgewerkt:
await client.data.Note.update(
{ id: 'note-123' },
{
title: 'Updated title',
updatedAt: new Date(),
}
);
Relaties bijwerken
Als u een relatie wilt wijzigen, geeft u de nieuwe gerelateerde entiteit of alleen de bijbehorende id door:
// Move a note to a different notebook
await client.data.Note.update(
{ id: 'note-123' },
{ notebook: { id: 'new-notebook-789' } }
);
Gegevens verwijderen
Gebruik de delete() methode om records te verwijderen die overeenkomen met een filter:
await client.data.Note.delete({ id: 'note-123' });
De methode wordt voltooid wanneer de backend de verwijdering bevestigt. Als er geen records overeenkomen met het filter, slaagt de methode nog steeds.
Maak een record aan of werk het bij
Gebruik upsert(where, create, update) om een ontbrekend record aan te maken of een bestaand bij te werken. Geef dezelfde ID in de zoekopdracht en het invoerveld voor aanmaken:
const id = '11111111-2222-3333-4444-555555555555';
const now = new Date();
await client.data.Note.upsert(
{ id },
{
id,
title: 'Daily summary',
content: 'Summary of today',
isPinned: false,
isArchived: false,
createdAt: now,
updatedAt: now,
user_id: 'user-123',
},
{ title: 'Daily summary', updatedAt: now },
);
Deze helper voert een leesbewerking uit, gevolgd door een aparte aanmaak of update. Het is niet atomair, en gelijktijdige oproepen kunnen racen. Gebruik het niet als een transactie- of garantie voor gelijktijdigheid.
Authenticatie afhandelen
Log in voordat je bewerkingen met beschermde gegevens uitvoert. Voor een gedeployeerde backend gebruik je de geconfigureerde Microsoft Entra inlogflow van de app. Het volgende voorbeeld van e-mail en wachtwoord is alleen voor een lokale backend:
await client.auth.signIn({ email, password });
// All subsequent data calls include authentication context
const notes = await client.data.Note.select(['id', 'title']).execute();
De client koppelt de verificatiesessie automatisch aan alle gegevens-API-aanroepen. U hoeft tokens niet handmatig door te geven.
Beste praktijken
- Selecteer alleen benodigde velden : haal alleen de velden op die u gebruikt om de nettolading te verkleinen en de prestaties te verbeteren.
-
Paginering gebruiken voor grote lijsten : vermijd het ophalen van duizenden records tegelijk met behulp van
first()enexecutePaginated(). - Batchrelatiequery's: gerelateerde entiteitsvelden opnemen in dezelfde query in plaats van afzonderlijke aanvragen te maken.
- Veelgebruikte gegevens in de cache opslaan: sla statische referentiegegevens op in het geheugen om API-aanroepen te verminderen.
Huidige beperkingen
- Een afzonderlijke
count()methode is niet beschikbaar. Gebruik de aggregatie van een numeriek veld, of tel items op alle pagina's. De lengte van een array telt alleen de records die op die pagina worden geretourneerd. - Veel-op-veel-relaties worden niet ondersteund. Gebruik een expliciete koppelentiteit met twee
@one()navigatiedecorators. - De eigenschap
totalCountopPagedResultwordt niet gevuld door de backend.