From harness-claude
Models one-to-one, one-to-many, many-to-many, and self-relations using @relation in Prisma schemas. Use for foreign key relationships, associations, self-references, and disambiguating multiple connections between models.
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeThis skill uses the workspace's default tool permissions.
> Model one-to-one, one-to-many, many-to-many, and self-relations with @relation in Prisma
Provides expert guidance on Prisma ORM for TypeScript apps: schema design, migrations, Prisma Client queries, relations, edge deployment, and performance optimization.
Provides expert guidance on Prisma ORM schema design, migrations, query optimization, relations modeling, and database operations for PostgreSQL, MySQL, SQLite.
Designs Prisma schemas with datasource, generator blocks, models, enums, field types, attributes, IDs, indexes, and native types for PostgreSQL, MySQL, SQLite. Useful for new projects or extending existing schemas.
Share bugs, ideas, or general feedback.
Model one-to-one, one-to-many, many-to-many, and self-relations with @relation in Prisma
@relation on the "many" side. The "one" side gets an array field:model User {
id String @id @default(cuid())
posts Post[]
}
model Post {
id String @id @default(cuid())
author User @relation(fields: [authorId], references: [id])
authorId String
}
@unique to the foreign key:model User {
id String @id @default(cuid())
profile Profile?
}
model Profile {
id String @id @default(cuid())
user User @relation(fields: [userId], references: [id])
userId String @unique
}
model Post {
id String @id @default(cuid())
tags Tag[]
}
model Tag {
id String @id @default(cuid())
posts Post[]
}
model PostTag {
post Post @relation(fields: [postId], references: [id])
postId String
tag Tag @relation(fields: [tagId], references: [id])
tagId String
assignedAt DateTime @default(now())
@@id([postId, tagId])
}
@relation to disambiguate:model Employee {
id String @id @default(cuid())
manager Employee? @relation("ManagerReports", fields: [managerId], references: [id])
managerId String?
reports Employee[] @relation("ManagerReports")
}
model User {
id String @id @default(cuid())
writtenPosts Post[] @relation("Author")
editedPosts Post[] @relation("Editor")
}
model Post {
id String @id @default(cuid())
author User @relation("Author", fields: [authorId], references: [id])
authorId String
editor User? @relation("Editor", fields: [editorId], references: [id])
editorId String?
}
onDelete and onUpdate behavior:author User @relation(fields: [authorId], references: [id], onDelete: Cascade, onUpdate: Cascade)
Options: Cascade, Restrict, NoAction, SetNull, SetDefault.
@@index([foreignKeyField]) on relation scalar fields for query performance.Prisma relations are defined at the Prisma schema level and map to foreign keys in the database. The @relation attribute is required on the side that stores the foreign key (the scalar field side).
Implicit vs explicit many-to-many: Implicit join tables follow the naming convention _ModelAToModelB (alphabetical). You cannot query the join table directly or add columns to it. Switch to explicit if you ever need metadata on the relationship.
Referential integrity modes:
foreignKeys (default for relational databases) — enforced by the databaseprisma — enforced by Prisma Client at the application level, required for databases that do not support foreign keys (e.g., PlanetScale with Vitess)Cascade gotchas:
onDelete: Cascade on a required relation means deleting a parent deletes all children — this is often not what you want for audit-sensitive dataonDelete: SetNull requires the foreign key field to be optional (String?)NoAction, which throws on violationPerformance considerations:
include on a relation triggers an additional SQL query (not a JOIN). For deeply nested includes, consider using raw queries with explicit JOINshttps://prisma.io/docs/orm/prisma-schema/data-model/relations