Bemærk
Adgang til denne side kræver godkendelse. Du kan prøve at logge på eller ændre mapper.
Adgang til denne side kræver godkendelse. Du kan prøve at ændre mapper.
Fabric Apps leverer en type-sikker GraphQL-klient, der lader dig udføre oprettelse, læsning, opdatering og sletning uden at skrive rå forespørgsler. Klienten genererer automatisk GraphQL fra dine metodekald og returnerer typede enheder baseret på dine datamodeldefinitioner.
Forudsætninger
- Et Fabric Apps-projekt med definerede datamodeller. Se Definér datamodeller.
- Backend-tjenesterne kører lokalt eller implementeres til Fabric.
Initialiser klienten
Instansier RayfinClient med din backend-URL, publicerbar nøgle og skematype:
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,
});
Det generiske typeargument gør det muligt for TypeScript at levere autofuldførelse og typekontrol for alle dataoperationer.
Disse eksempler antager, at du har aktiveret Data og registreret Note og Notebook i Universal App's packages/data/src/index.ts og shared schema-kontrakten. I en flad skabelon importerer du i stedet din skematype fra rayfin/data/schema.ts . Se Definér datamodeller.
Læs data
Få adgang til enhedssamlinger gennem client.data.<EntityName>. Fluent API'et tilbyder metoder til forespørgsler, filtrering, sortering og paginering.
Hent en side med optegnelser
execute() returnerer kun én side med 100 poster som standard. Den returnerer ikke markørmetadata eller henter efterfølgende sider. Brug fremadrettet paginering til lister, der kan vokse ud over én side.
const notes = await client.data.Note.select([
'id',
'title',
'content',
'createdAt',
'isPinned',
]).execute();
Hent en enkelt post efter primærnøgle
const note = await client.data.Note.findById('00000000-0000-0000-0000-000000000000');
findById() returnerer null , hvis der ikke findes nogen registrering. Den frigivne implementering vælger kun primærnøglen, så antag ikke, at andre entitetsfelter er fyldt ud. Vælg felter eksplicit, når du har brug for deres værdier:
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;
Filterposter
Brug metoden where() til at filtrere resultater:
const pinnedNotes = await client.data.Note.select([
'id',
'title',
'isPinned',
])
.where({ isPinned: { eq: true } })
.execute();
Filteroperatorer
| Operatør | Beskrivelse | Eksempel |
|---|---|---|
eq |
Lig med | { status: { eq: 'active' } } |
neq |
Ikke ligeværdige | { status: { neq: 'archived' } } |
gt |
Større end | { age: { gt: 18 } } |
gte |
Større end eller lig med | { age: { gte: 21 } } |
lt |
Mindre end | { price: { lt: 100 } } |
lte |
Mindre end eller lig med | { price: { lte: 50 } } |
contains |
Indeholder delstreng | { title: { contains: 'draft' } } |
Sortér resultater
Brug orderBy() til at sortere forespørgselsresultater:
const notes = await client.data.Note.select([
'id',
'title',
'createdAt',
])
.orderBy({ createdAt: 'desc' })
.execute();
Sorter efter flere kolonner:
const notes = await client.data.Note.select([
'id',
'title',
'isPinned',
'createdAt',
])
.orderBy({ isPinned: 'desc' })
.orderBy({ createdAt: 'desc' })
.execute();
Naviger i relationer
Når du definerer relationer med @one() og @many() decorators, kan du inkludere relaterede entitetsfelter i den samme forespørgsel:
const notes = await client.data.Note.select([
'id',
'title',
'content',
'notebook.id',
'notebook.name',
])
.execute();
Hver note indeholder sine tilhørende notesbogsdata uden at kræve en separat forespørgsel.
Paginer-store resultatsæt
Brug cursorbaseret paginering til store lister:
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);
Hent næste side med cursoren:
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();
}
Bemærkning
Backenden udfylder ikke egenskaben totalCount på typen PagedResult . Værdien page.items.length tæller kun den aktuelle side, ikke alle matchende poster.
For at behandle hver matchende post, fortsæt fremad, indtil hasNextPage er false. Hold valg, filtre og sorteringsrækkefølge uændrede på tværs af anmodninger.
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 giver ikke et øjebliksbillede på tværs af anmodninger. Samtidige ændringer kan påvirke de poster, du læser og tæller.
Aggregerede og gruppedata
Brug aggregate() til server-side totaler og groupBy() til opsummeringer pr. gruppe. Den selvstændige flydende count() metode er ikke tilgængelig, men count understøttes i en aggregeringsspecifikation.
Alle fem samlede operationer (sum, avg, , min, maxog count) kræver et numerisk felt. Tæl ikke en UUID id eller et tekstfelt. For eksempel antager følgende forespørgsel en registreret Product enhed med et krævet numerisk stockQuantity felt:
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 tæller ikke-nulværdier af det specificerede numeriske felt. Brug et nødvendigt numerisk felt til at tælle matchende rækker. Hvis din enhed ikke har et passende felt, skal du tælle identifikatorer på alle sider som vist tidligere, ikke kun på én side.
For grupperede totaler:
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);
}
Aggregeringsresultater er arrays med fields og aggregations objekter. En total har én række med et tomt fields objekt.
count returnerer a number; de øvrige operationer returnerer number | null for tomme eller helt nul input.
Ansøg where() før aggregering. Kombiner ikke aggregering med rækkevalg, rækkefølge eller bladring gennem select(), orderBy(), first(), eller after().
Opret poster
Brug create() metoden til at indsætte nye poster:
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',
});
Metoden returnerer den oprettede post, inklusive dens autogenererede id. Brug en eksplicit udvalgt læsning, når du har brug for yderligere lagrede felter.
Opret poster med relationer
Når du opretter enheder, der har relationer, skal enten det fulde relaterede objekt eller et objekt med kun primærnøglen blive sendt:
// 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(),
});
Begge former giver det samme resultat. Brug den første formular, når du allerede kender den relevante entitets ID og vil undgå en ekstra hent.
Klienten bruger det relaterede objekts primære nøgle til at sætte relationen. At sende et objekt opretter eller opdaterer ikke den relaterede notesbog.
Opdateringsposter
Brug metoden update() til at ændre eksisterende poster. Send et filterobjekt og et objekt, der indeholder felterne, for at opdatere:
await client.data.Note.update(
{ id: 'note-123' },
{
title: 'Updated title',
updatedAt: new Date(),
}
);
Opdater relationer
For at ændre en relation, send den nye relaterede enhed eller blot dens ID:
// Move a note to a different notebook
await client.data.Note.update(
{ id: 'note-123' },
{ notebook: { id: 'new-notebook-789' } }
);
Slet poster
Brug metoden delete() til at fjerne poster, der matcher et filter:
await client.data.Note.delete({ id: 'note-123' });
Metoden løses, når backend bekræfter sletning. Hvis ingen poster matcher filteret, lykkes metoden stadig.
Opret eller opdater en post
Brug upsert(where, create, update) den til at oprette en manglende post eller opdatere en eksisterende. Angiv samme ID i opslaget og skab inputtet:
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 },
);
Denne hjælper udfører en læsning efterfulgt af en separat oprettelse eller opdatering. Det er ikke atomar, og samtidige opkald kan løbe løb. Brug det ikke som en transaktion eller samtidig garanti.
Håndter autentificering
Log ind, før du udfører beskyttede dataoperationer. For en deployeret backend kan du bruge appens konfigurerede Microsoft Entra login-flow. Følgende eksempel på e-mail og adgangskode gælder kun for en lokal backend:
await client.auth.signIn({ email, password });
// All subsequent data calls include authentication context
const notes = await client.data.Note.select(['id', 'title']).execute();
Klienten tilknytter automatisk autentificeringssessionen til alle data-API-kald. Du behøver ikke at sende tokens manuelt.
Bedste praksis
- Vælg kun nødvendige felter – Hent kun de felter, du bruger, for at reducere payload-størrelsen og forbedre ydeevnen.
-
Brug paginering til store lister – Undgå at hente tusindvis af poster på én gang ved at bruge
first()ogexecutePaginated(). - Batch-relationsforespørgsler – Inkluder relaterede entitetsfelter i den samme forespørgsel i stedet for at lave separate anmodninger.
- Cache ofte tilgåede data – Gem statiske referencedata i hukommelsen for at reducere API-kald.
Gældende begrænsninger
- En selvstændig
count()metode er ikke tilgængelig. Brug en numerisk feltaggregering, eller tæl poster på tværs af alle sider. En arrays længde tæller kun de poster, der er angivet på den side. - Mange for mange relationer understøttes ikke. Brug en eksplicit join-enhed med to
@one()navigationsdekoratorer. - Ejendommen
totalCountpåPagedResulter ikke befolket af backend.