Relazioni
Tipi di Relazione
Prisma supporta tre tipi fondamentali di relazione: uno-a-uno (1:1), uno-a-molti (1:N) e molti-a-molti (N:M).
Relazione Uno-a-Uno (1:1)
Un record e’ collegato a esattamente un altro record.
model User {
id Int @id @default(autoincrement())
email String @unique
profile Profile?
}
model Profile {
id Int @id @default(autoincrement())
bio String
avatar String?
user User @relation(fields: [userId], references: [id])
userId Int @unique // @unique rende la relazione 1:1
}
// Creare utente con profilo
const user = await prisma.user.create({
data: {
email: 'mario@example.com',
profile: {
create: {
bio: 'Sviluppatore full-stack',
avatar: 'https://example.com/avatar.jpg',
},
},
},
include: { profile: true },
})
Relazione Uno-a-Molti (1:N)
Un record e’ collegato a molti altri record. E’ la relazione piu’ comune.
model User {
id Int @id @default(autoincrement())
email String @unique
name String
posts Post[]
}
model Post {
id Int @id @default(autoincrement())
title String
content String?
author User @relation(fields: [authorId], references: [id])
authorId Int
}
// Creare un utente con piu' post
const user = await prisma.user.create({
data: {
email: 'anna@example.com',
name: 'Anna',
posts: {
create: [
{ title: 'Primo post', content: 'Contenuto del primo post' },
{ title: 'Secondo post', content: 'Contenuto del secondo post' },
],
},
},
include: { posts: true },
})
// Trovare i post di un utente
const posts = await prisma.post.findMany({
where: { authorId: 1 },
include: { author: true },
})
Relazione Molti-a-Molti (N:M)
Relazione Implicita
Prisma crea automaticamente la tabella pivot:
model Post {
id Int @id @default(autoincrement())
title String
categories Category[]
}
model Category {
id Int @id @default(autoincrement())
name String @unique
posts Post[]
}
// Creare un post con categorie
const post = await prisma.post.create({
data: {
title: 'Guida Prisma',
categories: {
create: [
{ name: 'Database' },
{ name: 'TypeScript' },
],
},
},
include: { categories: true },
})
// Collegare categorie esistenti
const updated = await prisma.post.update({
where: { id: 1 },
data: {
categories: {
connect: [{ id: 3 }, { id: 5 }],
},
},
})
Relazione Esplicita
Quando la tabella pivot ha campi aggiuntivi:
model Post {
id Int @id @default(autoincrement())
title String
categories PostCategory[]
}
model Category {
id Int @id @default(autoincrement())
name String @unique
posts PostCategory[]
}
model PostCategory {
post Post @relation(fields: [postId], references: [id])
postId Int
category Category @relation(fields: [categoryId], references: [id])
categoryId Int
assignedAt DateTime @default(now())
assignedBy String
@@id([postId, categoryId])
}
Self-Relation
Un modello puo’ avere una relazione con se stesso, utile per strutture gerarchiche:
model Employee {
id Int @id @default(autoincrement())
name String
managerId Int?
manager Employee? @relation("ManagerToEmployee", fields: [managerId], references: [id])
reports Employee[] @relation("ManagerToEmployee")
}
// Creare un manager con dipendenti
const manager = await prisma.employee.create({
data: {
name: 'Marco Rossi',
reports: {
create: [
{ name: 'Luca Bianchi' },
{ name: 'Sara Verdi' },
],
},
},
include: { reports: true },
})
Relazioni Opzionali
Una relazione opzionale si definisce con ?. Il campo della chiave esterna deve essere anch’esso opzionale:
model Post {
id Int @id @default(autoincrement())
title String
author User? @relation(fields: [authorId], references: [id])
authorId Int? // Nullable: il post puo' non avere un autore
}
Azioni Referenziali (Cascading)
Puoi definire cosa succede quando un record referenziato viene eliminato o aggiornato:
model Post {
id Int @id @default(autoincrement())
title String
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
authorId Int
}
model Comment {
id Int @id @default(autoincrement())
text String
post Post @relation(fields: [postId], references: [id], onDelete: Cascade, onUpdate: Cascade)
postId Int
}
Azioni disponibili:
| Azione | Descrizione |
|---|---|
Cascade |
Elimina/aggiorna anche i record collegati |
Restrict |
Impedisce l’eliminazione se ci sono record collegati |
NoAction |
Simile a Restrict (dipende dal DB) |
SetNull |
Imposta la FK a null (il campo deve essere opzionale) |
SetDefault |
Imposta la FK al valore di default |
// Con Cascade: eliminare un utente elimina tutti i suoi post
await prisma.user.delete({
where: { id: 1 },
// Tutti i post di questo utente vengono eliminati automaticamente
})