Definieren von Datenmodellen für Fabric Apps

Fabric Apps verwendet TypeScript-Dekoratoren zum Definieren von Datenmodellen, die Datenbanktabellen und APIs generieren. Sie definieren jede Entität als Klasse, die mit @entity()versehen ist, Fügen Sie Felddekortoren für Datentypen hinzu und ordnen Sie Beziehungen zwischen Entitäten zu.

Anweisungen zur Autorisierung und Zugriffssteuerung finden Sie unter Definieren von Datenberechtigungen.

Voraussetzungen

  • Ein Fabric Apps-Projekt, das mit npm create @microsoft/rayfin@latest erstellt oder mit npx rayfin init initialisiert wurde.
  • Grundlegendes Verständnis von TypeScript-Klassen und Dekorateuren.

Definieren einer Entität

Die Standardvorlage blankapp erstellt einen universellen App-Arbeitsbereich bei deaktivierter Datenfunktion. Aktivieren Sie dies mithilfe der Datenmodellierungsfunktion der Vorlage:

npm run pack:add -- data-modeling

Dieser Schritt fügt eine Starterentität und einen freigegebenen Vertrag hinzu. Fügen Sie Entitätenklassen in packages/data/src/ ein, registrieren Sie sie in packages/data/src/index.ts, und pflegen Sie ihre clientseitigen Verträge in packages/shared/src/index.ts. Der Datendienst verwendet services.data.path: packages/data in rayfin/rayfin.yml. Wenn du Data manuell für Fabric konfigurierst, setze auch enabled: true und dialect: mssql.

Flache Vorlagen können stattdessen Entitäten in rayfin/data/ behalten und rayfin/data/schema.ts verwenden. Folgen Sie Ihren konfigurierten Servicepfaden, anstatt einen zweiten Datenordner zu erstellen. Siehe Projektstruktur.

Um ein Datenmodell zu erstellen, fügen Sie den @entity() Dekorateur einer TypeScript-Klasse hinzu. Importieren Sie dann die erforderlichen Dekoratoren aus @microsoft/rayfin-core:

import { entity, uuid, text, date } from '@microsoft/rayfin-core';

@entity()
export class Todo {
  @uuid() id!: string;
  @text({ max: 200 }) title!: string;
  @text({ optional: true, max: 2000 }) description?: string;
  @date() createdAt!: Date;
  @date() updatedAt!: Date;
}

Diese Entität generiert eine Todo Tabelle mit Spalten für id, title, , description, createdAtund updatedAt.

Important

Geben Sie gespeicherten Textfeldern eine explizite maximale Länge, die für Ihre Daten angemessen ist. Auf Microsoft SQL Server generiert Text ohne NVARCHAR(MAX)max, was die Erzeugung von GraphQL-Metadaten verhindern kann. Die Beispiele verwenden durch Trennzeichen begrenzten Text, einschließlich Owner- und Fremdschlüssel-Zeichenfolgen. Siehe Probleme mit Datenmodellen beheben.

Primärschlüssel

Jede Entität verwendet ein UUID-Feld string , das als Primärschlüssel bezeichnet wird id . Wenn Sie id nicht explizit deklarieren, fügt Fabric Apps es dem Schema automatisch hinzu.

  • Das id Feld ist bei Erstellungsvorgängen optional – der Server generiert eine UUID, wenn Sie es weglassen.
  • Sie können bei der Erstellung Ihre eigene UUID angeben, wenn Sie clientseitig generierte Bezeichner bevorzugen.
  • Zusammengesetzte Primärschlüssel und benutzerdefinierte Schlüsselnamen werden nicht unterstützt.
@entity()
export class Note {
  @uuid() id!: string;  // UUID primary key, auto-generated when omitted
  @text({ max: 200 }) title!: string;
  @text({ max: 4000 }) content!: string;
}

Unterstützte Datentypen

Verwenden Sie diese Dekoratoren, um Feldtypen zu definieren:

Dekorateur Typ Description
@uuid() Schnur Feld für eindeutige Kennung.
@text({ max: n }) Schnur Textfeld mit einer expliziten maximalen Länge für persistierte MSSQL-Spalten.
@int() Zahl Ganzzahliges Feld.
@decimal() Zahl Dezimal- oder numerisches Feld.
@boolean() Boolescher Wert True- oder False-Feld.
@date() Date Datums- und Uhrzeitfeld, serialisiert aus ISO-Zeichenfolgen oder Date -Objekten.
@email() Schnur Textfeld mit E-Mail-Überprüfung.
@set() Schnur Aufzählung von String-Literalen.

Beispiel mit mehreren Typen

import { entity, uuid, text, int, decimal, boolean, date, set } from '@microsoft/rayfin-core';

@entity()
export class Product {
  @uuid() id!: string;
  @text({ max: 200 }) name!: string;
  @decimal() price!: number;
  @int() stockQuantity!: number;
  @boolean() isAvailable!: boolean;
  @date() createdAt!: Date;
  @set('draft', 'published', 'archived') status!: 'draft' | 'published' | 'archived';
}

Typmodifizierer

Fügen Sie Felddekoratoren Modifizierer hinzu, um Validierungen und Einschränkungen zu konfigurieren:

Modifizierer Description
{ optional: true } Lässt NULL-Werte zu. Felder sind standardmäßig erforderlich.
{ unique: true } Fügen Sie eine eindeutige Einschränkung hinzu.
{ default: value } Legen Sie einen Standardwertausdruck fest.
{ max: n }, { min: n } Zeichenfolgenlängeneinschränkungen (maximale und minimale Anzahl von Zeichen).
{ min: n }, { max: n } Einschränkungen für numerische Werte.

Hinweis

Die optionale TypeScript-Markierung (? nach einem Eigenschaftsnamen) wirkt sich nur auf den statischen TypeScript-Typ aus. Dadurch wird die Datenbankspalte nicht NULL-fähig. Um ein Feld als nullable zu kennzeichnen, fügen Sie { optional: true } zum Decorator hinzu. Wird ! verwendet, um zu bestätigen, dass ein erforderliches Feld vom Framework initialisiert wird.

Beispiel mit Modifizierern

@entity()
export class User {
  @uuid() id!: string;
  @email({ unique: true, max: 254 }) email!: string;
  @text({ min: 3, max: 50 }) username!: string;
  @text({ optional: true, max: 500 }) bio?: string;
  @int({ min: 0, max: 150 }) age!: number;
  @boolean({ default: false }) isVerified!: boolean;
}

Definieren von Beziehungen

Verwenden Sie die Dekoratoren @one() und @many(), um Navigationseigenschaften zwischen Entitäten zu definieren. Fabric Apps generiert automatisch Fremdschlüsselspalten, wenn Sie Beziehungen definieren.

  • 1:n – Wird für das Übergeordnete und @many() das Kind verwendet@one().
  • Viele-zu-eins – Verwenden Sie @one() für das untergeordnete Element, um auf das übergeordnete Element zu verweisen.
  • Viele-zu-viele-Beziehungen werden nicht unterstützt – verwenden Sie stattdessen eine explizite Verknüpfungsentität.

Beispiel für 1:n-Beziehung

import { entity, uuid, text, date, one, many } from '@microsoft/rayfin-core';

@entity()
export class Notebook {
  @uuid() id!: string;
  @text({ max: 200 }) name!: string;
  @date() createdAt!: Date;
  @many(() => Note) notes?: Note[];
}

@entity()
export class Note {
  @uuid() id!: string;
  @text({ max: 200 }) title!: string;
  @text({ max: 4000 }) content!: string;
  @date() createdAt!: Date;
  @text({ max: 36 }) notebook_id!: string;
  @one(() => Notebook) notebook?: Notebook;
}

Wenn Sie @one(() => Notebook) für die Entität Note definieren, erstellt Fabric Apps automatisch eine notebook_id Fremdschlüsselspalte. Deklarieren Sie das Fremdschlüsselfeld explizit nur, wenn Sie beabsichtigen, es im Anwendungscode zu lesen oder festzulegen.

Benennungskonvention für Fremdschlüssel

Wenn Sie ein Fremdschlüsselfeld definieren, verwenden Sie die {property}_id Benennungskonvention:

@entity()
export class Note {
  @uuid() id!: string;
  @text({ max: 36 }) notebook_id!: string;      // Foreign key field
  @one(() => Notebook) notebook?: Notebook;  // Navigation property
}

Benutzerdefinierte Fremdschlüsselnamen (foreignKey, targetKey Optionen) werden nicht unterstützt.

Referenzsystementitäten

Fabric Apps unterstützt keine @one() Beziehungen, die auf Systementitäten verweisen, z. B. die integrierte USER-Entität. Um eine Zeile mit dem angemeldeten Benutzer zu verknüpfen, fügen Sie ein beschränktes user_id Textfeld hinzu und füllen es aus den Authen-Claims aus (typischerweise claims.sub):

@entity()
export class Task {
  @uuid() id!: string;
  @text({ max: 200 }) title!: string;
  @text({ max: 255 }) user_id!: string;  // System user ID from claims.sub
}

Filtern Sie Zeilen mithilfe von user_id in Ihren Rollenrichtlinien, um benutzerspezifischen Zugriff zu erzwingen.

Registrieren von Entitäten im Schema

Registrieren Sie in einem Universal App-Arbeitsbereich Laufzeit-Entitätsklassen in packages/data/src/index.ts:

import { Note } from './Note.js';
import { Notebook } from './Notebook.js';

export const schema = [Note, Notebook];

Halten Sie die entsprechenden Datensatz-Schnittstellen und UniversalAppSchema Map in packages/shared/src/index.ts an diesen Entitäten ausgerichtet. Das Frontend importiert UniversalAppSchema aus @rayfin-app/shared; es importiert keine dekorierten Laufzeitklassen. Fügen Sie Product zu beiden Registrierungen hinzu, wenn Sie die numerischen Aggregationsbeispiele in Read and write data verwenden.

Für eine Alternative mit flacher Vorlage ordnen Sie Entitätstypen in rayfin/data/schema.ts zu:

import type { Note } from './Note.js';
import type { Notebook } from './Notebook.js';

export type NotesAppSchema = {
  Note: Note;
  Notebook: Notebook;
};

Aktualisieren Sie die Registrierungen und Schematypen für Ihr gewähltes Layout, wann immer Sie eine neue Entität erstellen.

Schemaänderungen anwenden

Nach der Definition oder Änderung der Entitäten wenden Sie die Änderungen in der Datenbank an. Für den vollständigen Bereitstellungs- und Verifikationsworkflow siehe Schemaänderungen anwenden und verifizieren.

  1. Stellen Sie das aktualisierte Schema für Fabric bereit:

    npx rayfin up db apply
    
  2. Wenn die Schemaänderung destruktive Vorgänge (Ablegen von Spalten, Umbenennen von Tabellen) enthält, warnt Sie die CLI und lehnt den Vorgang ab. Verwenden Sie --force diese Option, um die Sicherheitsüberprüfung außer Kraft zu setzen:

    npx rayfin up db apply --force
    

Hinweis

Die Verwendung --force kann zu Datenverlust führen. Überprüfen Sie die aufgelisteten Vorgänge sorgfältig, bevor Sie fortfahren.

Bewährte Methoden

  • Definieren Sie Fremdschlüsselfelder nur, wenn Sie sie im Code lesen oder setzen müssen – Fabric Apps generiert sie automatisch aus Navigations-Decorators.
  • Verwenden Sie relative Importe mit .js Erweiterungen in Entitätsdateien, damit das ausgegebene ESM-JavaScript ordnungsgemäß aufgelöst wird.
  • Informationen zu Autorisierungsmustern und rollenbasiertem Zugriff finden Sie unter Definieren von Datenberechtigungen.

Troubleshooting

Fehlende Beziehungen

Wenn Beziehungen nicht in der API angezeigt werden, überprüfen Sie Folgendes:

  • Der Navigationsdekorator (@one() oder @many()) ist vorhanden.
  • Die Entität ist in Ihrem konfigurierten Datenpaket und dem gemeinsamen Schema registriert oder in rayfin/data/schema.ts bei einer flachen Vorlage.