PrismaORM_Header

Prisma ORM: Ein Überblick über die moderne ORM-Lösung für TypeScript und Node.js

Von am 22.01.2025

Datenbanken sind in vielen modernen Anwendungen nicht wegzudenken – doch SQL-Abfragen können schnell komplex und Datenbank-Migrationen können auf Dauer mühsam werden. Hier kommt Prisma ORM ins Spiel: Ein innovatives Tool, das die Arbeit mit Datenbanken erheblich vereinfacht. Prisma verbindet Typsicherheit, Automatisierung und Benutzerfreundlichkeit und bietet damit alles, was für eine effiziente Entwicklung benötigt wird. Dieser Beitrag soll nach einer kurzen theoretischen Einführung vor allem praktisch erklären wie Prisma ORM beispielhaft innerhalb eines NestJS-Projekts verwendet werden kann.

Was ist Prisma ORM?

Prisma ORM ist, wie der Name schon verrät, ein ORM (object-relational mapping), also eine Objektrelationale Abbildung für TypeScript und Node.js. ORMs abstrahieren die Komplexität der Datenbank, indem sie über Objekte eine Schnittstelle zum Holen, Erstellen, Bearbeiten und Löschen von Daten bieten. Es werden Modelle bzw. Klassen geschrieben, die den Tabellen in der Datenbank entsprechen. Prisma ORM verfolgt dabei allerdings einen schema-first Ansatz. Das bedeutet, dass es ein zentrales Schema-File gibt, auf dem alles basiert. Außerdem ist Prisma ORM open-source (bis auf Prisma Sudio – siehe nächster Abschnitt).

Bestandteile

Prisma besteht aus folgenden drei Teilen:

  • Prisma Client
  • Prisma Migrate
  • Prisma Studio

Prisma Client

Der Prisma Client ist eine automatisch basierend auf dem Prisma-Schema generierte, typsichere API, mit der Datenbankabfragen durchgeführt werden können. Es muss also nicht manuell SQL geschrieben werden und durch die Typsicherheit werden Fehler frühzeitig vermieden. Dieser Bestandteil ist der Teil von Prisma ORM, der am häufigsten vorkommt, weshalb er oftmals auch nur Prisma genannt wird.

Prisma Migrate

Prisma Migrate ist ein Tool zum Verwalten von Datenbankschemas. In Form von Migrationen können leicht Änderungen an der Struktur der Datenbank vorgenommen werden. Dadurch können Code und Datenbank synchron gehalten werden.

Prisma Studio

Prisma Studio bietet einen grafische Benutzeroberfläche, um die Datenbank durchsuchen zu können und die Daten verwalten zu können. Auf diesen Teil wird in dem Blogartikel nicht genauer eingegangen.

Erste Schritte

Im folgenden Abschnitt wird nun erklärt wie Prisma ORM beispielhaft in einem NestJS Projekt installiert und verwendet werden kann.

1. Projekt aufsetzen

Zuerst muss NestJS CLI installiert und ein neues Projekt erstellt werden. Wenn ein bestehendes Projekt verwendet wird, kann dieser Schritt übersprungen werden

npm i -g @nestjs/cli
nest new prisma-test

Im Ordner des Projekts, muss nun Prisma CLI installiert und ein neues Prisma-Projekt initialisiert werden.

npm i prisma --save-dev
npx prisma init

Nun muss die Datenbankverbindung hergestellt werden. Dazu muss im .env File die richtige URL gesetzt (siehe dazu https://www.prisma.io/docs/orm/reference/connection-urls) und in der schema.prisma Datei der provider im datasource Block angepasst werden. Ich arbeite lokal mit XAMPP und einer MySQL Datenbank. Prisma ORM kann aber mit PostgreSQL, MySQL, MariaDB, SQLite, MongoDB, Supabase und vielen weiteren Datenbanken genutzt werden.

2. Tabellen erstellen

Um Tabellen zu erstellen, müssen zuerst Models im Prisma Schema erstellt werden. Das prisma.schema File könnte beispielsweise so aussehen:

model User {
  id       Int    @id @default(autoincrement())
  username String @unique
  posts    Post[]
}

model Post {
  id        Int      @id @default(autoincrement())
  title     String
  text      String?
  published Boolean? @default(false)
  author    User?    @relation(fields: [authorId], references: [id])
  authorId  Int?
}

Zuerst wird der Name des Feldes definiert, dann der Typ (? für optional) angegeben und abschließend die Eigenschaften angeführt.


Hinweis zu VS Code:

Arbeitet man in VS Code, so empfiehlt es sich, die Extension “Prisma” von Prisma selbst herunterzuladen, um die Lesbarkeit des Schemas durch Syntax Highlighting zu verbessern.


Nachdem die Datei gespeichert wurde, können nun mittels Prisma Migrate die Migration Files erstellt werden, die dann unter prisma/migrations zu finden sind.

npx prisma migrate dev --name init

3. Prisma Client installieren und verwenden

npm i @prisma/client

Mit der Installation wird auch schon prisma generate ausgeführt. In der Zukunft muss nach jeder Änderung am Model dieser Befehl ausgeführt werden, um den Prisma Client up-to-date zu halten.

Nun erstellen wir ein Prisma Service (prisma.service.ts) im src Ordner, welches wir dann in anderen Services verwenden können.

import { Injectable, OnModuleInit } from '@nestjs/common';
import { PrismaClient } from '@prisma/client';

@Injectable()
export class PrismaService extends PrismaClient implements OnModuleInit {
  async onModuleInit() {
    await this.$connect();
  }
}

Um ein Module, ein Service und einen Controller in NestJS zu erstellen werden folgende Befehle benötigt:

nest g mo user
nest g s user
nest g co user

Dasselbe macht man für die Posts. Dann kann das User Service erweitert werden. Um das Prisma Service verwenden zu können, muss es im App Module und jedem weiteren wie z.B. User Module unter Providers hinzugefügt werden.

So könnte das User Service aussehen:

import { Injectable } from '@nestjs/common';
import { PrismaService } from '../prisma.service';
import { Prisma, User } from '@prisma/client';

@Injectable()
export class UserService {
    constructor(private prisma: PrismaService) { }

    async findUserById(
        id: number,
    ): Promise<User | null> {
        return this.prisma.user.findUnique({
            where: { id },
        });
    }

    async findAllUsers(): Promise<User[]> {
        return this.prisma.user.findMany();
    }

    async createUser(data: Prisma.UserCreateInput): Promise<User> {
        return this.prisma.user.create({
            data,
        });
    }

    async updateUser(params: {
        id: number;
        data: Prisma.UserUpdateInput;
    }): Promise<User> {
        const { id, data } = params;
        return this.prisma.user.update({
            where: { id },
            data: data
        });
    }

    async deleteUser(id: number): Promise<User> {
        return this.prisma.user.delete({
            where: { id }
        });
    }
}

Das Prisma Service (bzw. der Prisma Client) stellt einem die CRUD Methoden zur Verfügung und auch die Types können direkt von Prisma übernommen werden. Nach demselben Prinzp kann das Post Service erweitert werden.

Möchte man beim Laden eines Posts auch die Informationen des Autors bzw. der Autorin mitgeben, so kann include oder select verwendet werden.

async findPostById(
        id: number,
    ): Promise<Post | null> {
        return this.prisma.post.findUnique({
            where: { id },
            include: {
                author: true
            }
        });
    }

Es gibt unzählige Query Optionen, die verwendet werden können um nach bestimmten Daten zu suchen, sortieren, filtern etc. Siehe https://www.prisma.io/docs/orm/prisma-client/queries.

4. Endpoints definieren

In den Controllern definiert man dann seine Endpoints und ruft die Methoden des spezifischen Services auf.

import { Body, Controller, Get, Post } from '@nestjs/common';
import { UserService } from './user.service';
import { User } from '@prisma/client';

@Controller('user')
export class UserController {
    constructor(
        private readonly userService: UserService,
    ) { }

    @Post()
    async createUser(
        @Body() userData: { username: string; },
    ): Promise<User> {
        return this.userService.createUser(userData);
    }

    @Get()
    async getAllUsers(): Promise<Array<User>> {
        return this.userService.findAllUsers();
    }
}

Da dies NestJS spezifisch ist und nichts direkt mit Prisma zu tun hat, wird darauf hier nicht näher eingegangen.

Mit npm run start:dev kann die Applikation gestartet werden.

Fazit

Prisma ORM vereinfacht den Umgang mit der Datenbank erheblich und ist leicht zu erlernen. Im Vergleich zu anderen ORMs wie zum Beipsiel TypeORM werden die Models genau in einem File, dem Prisma Schema, definiert und alles andere wird basierend darauf generiert. Bei TypeORM hingegen definiert man zuerst die Entity-Klassen in mehreren Dateien und versieht die enthaltenen Properties mit Decoratorn, woraufhin TypeORM diese in Datenbank Informationen verwandelt. Bei Prisma ORM sind außerdem die automatisch generierten Types sehr praktisch. Und was dabei aber nie verloren geht, sind die Personalisierungsmöglichkeiten bei den Queries.

Quellen

https://www.prisma.io/docs/orm/overview/prisma-in-your-stack/is-prisma-an-orm

https://medium.com/@binayakgourishankar/getting-started-with-prisma-orm-89c2fcda5026

https://docs.nestjs.com/recipes/prisma

https://dev.to/afl_ext/prisma-vs-typeorm-description-and-comparison-4bob

https://www.prisma.io/docs/orm/overview/databases

Logo vom Beitragsbild

https://github.com/prisma/presskit

Beitrag kommentieren

(*) Pflichtfeld