Datan lukeminen ja kirjoittaminen GraphQL:llä Fabric Appsissa

Fabric Apps tarjoaa tyyppiturvallisen GraphQL-asiakasohjelman, jonka avulla voit suorittaa luomis-, luku-, päivitys- ja poistotoimintoja ilman raakakyselyiden kirjoittamista. Asiakas generoi GraphQL:n automaattisesti metodikutsuistasi ja palauttaa tyypitetyt entiteetit datamallin määritelmien perusteella.

Edellytykset

  • Fabric Apps -projekti, jossa on määritelty datamallit. Katso Määrittele tietomallit.
  • Backend-palvelut toimivat paikallisesti tai Fabric-palveluissa.

Alusta asiakas

Käynnistä RayfinClient backend-URL-osoitteesi, julkaistava avain ja skeematyyppi:

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,
});

Yleinen tyyppiargumentti mahdollistaa TypeScriptin automaattisen täydennyksen ja tyypintarkistuksen kaikille dataoperaatioille.

Nämä esimerkit olettavat, että olet ottanut Data käyttöön ja rekisteröitynyt Note sekä Notebook Universal Appin packages/data/src/index.ts ja jaetun skeeman sopimuksessa. Tasaisessa mallipohjassa tuo skeematyyppi rayfin/data/schema.ts sen sijaan. Katso Määrittele tietomallit.

Tietojen lukeminen

Pääsy entiteettikokoelmiin kautta client.data.<EntityName>. Fluent API tarjoaa menetelmiä kyselyihin, suodatuksiin, lajitteluun ja sivuttamiseen.

Hae sivu tietoja

execute() palauttaa vain yhden sivun, oletuksena 100 tietueessa. Se ei palauta kursorimetatietoja eikä hae seuraavia sivuja. Käytä eteenpäin suuntautuvaa sivutusta listoille, jotka voivat kasvaa yli yhden sivun.

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

Hae yksi tietue ensisijaisen avaimen mukaan

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

findById() palautetaan null , jos merkintää ei ole. Vapautettu toteutus valitsee vain ensisijaisen avaimen, joten älä oleta, että muut entiteettikentät ovat täytettyjä. Valitse kentät nimenomaan silloin, kun tarvitset niiden arvoja:

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;

Suodatintietueet

Käytä menetelmää where() tulosten suodattamiseen:

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

Suodatinoperaattorit

Operaattori Description Esimerkki
eq Yhtä suuri kuin { status: { eq: 'active' } }
neq Ei tasa-arvoisia { status: { neq: 'archived' } }
gt Suurempi kuin { age: { gt: 18 } }
gte Suurempi tai yhtä suuri kuin { age: { gte: 21 } }
lt Pienempi kuin { price: { lt: 100 } }
lte Pienempi tai yhtä suuri kuin { price: { lte: 50 } }
contains Sisältää alijonon { title: { contains: 'draft' } }

Lajittele tulokset

Käytä orderBy() kyselytulosten lajittelua:

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

Lajittele useiden sarakkeiden mukaan:

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

Kun määrittelet suhteita ja @one()@many() koristelijoiden kanssa, voit sisällyttää samaan kyselyyn liittyvät entiteettikentät:

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

Jokainen muistiinpano sisältää siihen liittyvän muistikirjan tiedot ilman erillistä kyselyä.

Suuret tulosjoukot paginoi

Käytä kursoripohjaista sivutusta suurissa listoissa:

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

Hae seuraava sivu osoittimella:

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();
}

Note

Taustajärjestelmä ei täytä totalCount ominaisuutta kyseisessä PagedResult tyypissä. Arvo page.items.length laskee vain nykyisen sivun, ei kaikkia vastaavia tietueita.

Jokaisen vastaavan tietueen käsittelemiseksi jatketaan eteenpäin, kunnes hasNextPage on false. Pidä valinnat, suodattimet ja lajittelujärjestys muuttumattomina toiveiden välillä.

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

Sivuttaminen ei anna tilannekuvaa pyyntöjen välillä. Samanaikaiset muutokset voivat vaikuttaa lukemiisi ja laskemiisi tietueisiin.

Yhteenveto- ja ryhmädata

Käytä aggregate() palvelinpuolen kokonaismääriin ja groupBy() ryhmäkohtaisiin yhteenvetoihin. Itsenäinen sujuva count() menetelmä ei ole saatavilla, mutta count se on tuettu aggregaatiospesifikaatiossa.

Kaikki viisi aggregaattioperaatiota (sum, avg, maxmin, , ja count) vaativat numeerisen kentän. Älä laske UUID id :tä tai tekstikenttää. Esimerkiksi seuraava kysely olettaa rekisteröidyn Product yksikön, jolla on vaadittu numeerinen stockQuantity kenttä:

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 laskee määritellyn numeerisen kentän ei-nollaarvot. Käytä vaadittua numeerista kenttää laskeaksesi vastaavia rivejä. Jos yksikölläsi ei ole sopivaa kenttää, laske tunnisteet kaikilta sivuilta kuten aiemmin näytettiin, ei vain yhdelle sivulle.

Ryhmitellyille kokonaisluvuille:

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);
}

Aggregaatiotulokset ovat taulukoita, joilla fields on ja aggregations objektit. Kokonaissummassa on yksi rivi, jossa on tyhjä fields objekti. count palauttaa a number; muut operaatiot palaavat number | null tyhjille tai kokonaan nollatuloille.

Hae where() ennen aggregointia. Älä yhdistä aggregointia rivin valintaan, järjestykseen tai sivuttamiseen select(), orderBy(), first(), tai after().

Luo tietueita

Käytä menetelmää create() uusien tietueiden lisäämiseen:

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',
});

Metodi palauttaa luodun tietueen, mukaan lukien automaattisesti luodun id. Käytä eksplisiittistä valittua lukua, kun tarvitset lisätallennettuja kenttiä.

Luo tietueita suhteilla

Kun luodaan entiteettejä, joilla on suhteita, välitä joko koko siihen liittyvä olio tai olio, jolla on vain pääavain:

// 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(),
});

Molemmat muodot tuottavat saman lopputuloksen. Käytä ensimmäistä lomaketta, kun tiedät jo kyseisen yksikön tunnuksen ja haluat välttää ylimääräisen noudon.

Asiakas käyttää liittyvän objektin ensisijaista avainta suhteen asettamiseen. Objektin välittäminen ei luo tai päivitä siihen liittyvää muistikirjaa.

Päivitä tilastot

Käytä menetelmää update() muokkaaaksesi olemassa olevia tietueita. Välitä suodatinobjekti ja objekti, joka sisältää kentät päivitettäväksi:

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

Päivitä suhteet

Suhteen muuttamiseksi anna uusi liittyvä taho tai pelkkä sen tunnus:

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

Poista tietueet

Käytä delete() menetelmää poistaaksesi tietueet, jotka vastaavat suodatinta:

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

Menetelmä ratkeaa, kun taustajärjestelmä vahvistaa poiston. Jos mikään tietue ei vastaa suodatinta, menetelmä onnistuu silti.

Luo tai päivitä tietue

Käytä upsert(where, create, update) puuttuvan tietueen luomiseen tai olemassa olevan päivittämiseen. Anna sama ID hakuun ja create-inputiin:

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 },
);

Tämä apuväline suorittaa lukemisen ja sen jälkeen erillisen luomisen tai päivityksen. Se ei ole atominen, ja samanaikaiset kutsut voivat kilpailla. Älä käytä sitä transaktiona tai rinnakkaistakuuna.

Käsittele todennus

Kirjaudu sisään ennen suojattujen tietojen suorittamista. Käyttöönotetussa taustajärjestelmässä käytä sovelluksen konfiguroitua Microsoft Entra -kirjautumisvirtaa. Seuraava sähköpostiosoite ja salasana -esimerkki on tarkoitettu vain paikalliselle taustajärjestelmälle:

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

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

Asiakas liittää tunnistautumisistunnon automaattisesti kaikkiin data-API-kutsuihin. Sinun ei tarvitse siirtää tokeneita manuaalisesti.

Parhaat käytännöt

  • Valitse vain tarvittavat kentät – Hae vain ne kentät, joita käytät hyötykuorman pienentämiseksi ja suorituskyvyn parantamiseksi.
  • Käytä sivuttamista suurissa listoissa – Vältä tuhansien tietueiden hakemista kerralla käyttämällä first() ja executePaginated().
  • Eräaikaiset suhdekyselyt – Sisällytä siihen liittyvät entiteettikentät samaan kyselyyn sen sijaan, että tekisit erillisiä pyyntöjä.
  • Välimuisti usein käytetty data – Tallenna staattinen viitedata muistiin API-kutsujen vähentämiseksi.

Nykyiset rajoitukset

  • Erillistä count() menetelmää ei ole saatavilla. Käytä numeerisen kentän aggregaatiota tai laske tietueita kaikilta sivuilta. Taulukon pituus laskee vain ne tietueet, jotka palautetaan kyseisellä sivulla.
  • Moni-to-monen suhteita ei tueta. Käytä eksplisiittistä liitosyksikköä kahden @one() navigointisisustelijan kanssa.
  • Alueella totalCount oleva kiinteistö PagedResult ei ole taustajärjestelmän täyttämä.