Lección 2 de 17 · Lectura y práctica
Diseñar un Schema con Relaciones y Validaciones
Concepto claveDiseñar un schema en Prisma es como crear los planos de un edificio antes de construirlo. Define la estructura de tu base de datos, incluyendo tablas (modelos), columnas (campos) y cómo se conectan entre sí.
Del concepto a la práctica
Taller de esta lección
Una relación útil debe expresar tanto la dirección como la regla de propiedad. Para una agenda de salas, Reservation pertenece a un User y a una Room; sus claves foráneas no deben confundirse con una validación de fechas, que requiere lógica adicional.
Ejemplo resuelto
model Reservation {
id Int @id @default(autoincrement())
startsAt DateTime @db.Timestamptz(3)
endsAt DateTime @db.Timestamptz(3)
userId Int
roomId Int
user User @relation(fields: [userId], references: [id])
room Room @relation(fields: [roomId], references: [id])
@@index([roomId, startsAt])
}El índice acompaña la consulta prevista por sala y comienzo.
Reservation es un fragmento: User yRoom deben existir con la relación inversa para validar el schema. Añade modelos mínimos:
model User {
id Int @id
name String
reservations Reservation[]
}
model Room {
id Int @id
code String @unique
name String
capacity Int
reservations Reservation[]
}Para las lecciones de estados añade enum ReservationStatus con PENDING,CONFIRMED,CANCELLED, status ReservationStatus @default(PENDING) y externalRef String @unique en Reservation. Rechaza endsAt<=startsAt, no solo fechas invertidas. PostgreSQL con foreign keys impide referencias ausentes; relationMode prisma no ofrece la misma garantía de base de datos. El índice ayuda al acceso, sin impedir solapamientos por sí solo.
Pruébalo
Enumera entidades y propietarios.
Separa restricciones estructurales de reglas de negocio.
Añade claves foráneas e índices de búsqueda.
Prueba una reserva con fechas invertidas en la capa de aplicación.
Comprueba tu resultado
La base rechaza una sala inexistente y la aplicación rechaza endsAt anterior a startsAt.
Error frecuente: asumir que un tipo DateTime valida el orden entre dos campos. Corrígelo con una comprobación explícita antes de escribir.
Ejercicio: crea dos usuarios, una sala y una reserva; verifica que la relación devuelve exactamente un usuario y una sala.

Mapa de prácticaUna clave conecta cada pedido con su cliente. INNER JOIN devuelve las coincidencias y puede producir varias filas por cliente. LEFT JOIN conserva también los clientes sin pedido y representa los campos ausentes con NULL.
Ver la infografía en tamaño completo ↗Concepto clave
Diseñar un schema en Prisma es como crear los planos de un edificio antes de construirlo. Define la estructura de tu base de datos, incluyendo tablas (modelos), columnas (campos) y cómo se conectan entre sí (relaciones). En producción, un buen schema no solo organiza los datos, sino que también previene errores mediante validaciones y optimiza el rendimiento desde el inicio.
Imagina que estás diseñando una plataforma de e-commerce. Necesitas modelos para Usuario, Producto y Pedido. Las relaciones entre ellos (un usuario puede tener muchos pedidos, un pedido puede contener varios productos) son cruciales para consultas eficientes. Las validaciones aseguran que, por ejemplo, el precio de un producto nunca sea negativo o que un email tenga formato correcto, evitando datos corruptos que podrían romper tu aplicación en producción.
Cómo funciona en la práctica
Primero, defines tus modelos en el archivo schema.prisma. Cada modelo se traduce a una tabla en la base de datos. Para relaciones, usas campos especiales que conectan modelos, como @relation. Las validaciones se aplican directamente en los campos con atributos como @unique, @default, o restricciones de tipo.
Paso a paso: 1) Identifica las entidades principales de tu aplicación (ej: Usuario, Producto). 2) Define los campos de cada modelo con tipos de datos precisos (ej: String, Int, DateTime). 3) Establece relaciones usando claves foráneas implícitas o explícitas. 4) Añade validaciones para integridad de datos. 5) Ejecuta prisma migrate dev para generar migraciones que aplican el schema a la base de datos.
Código en acción
Aquí un ejemplo funcional para un sistema de blog con usuarios y posts, incluyendo relaciones y validaciones básicas:
// schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
email String @unique
name String?
posts Post[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
}
model Post {
id Int @id @default(autoincrement())
title String @db.VarChar(200)
content String?
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id])
authorId Int
createdAt DateTime @default(now())
}
Ahora, mejorémoslo para producción añadiendo validaciones avanzadas y una relación muchos-a-muchos para etiquetas:
// schema.prisma mejorado
model User {
id Int @id @default(autoincrement())
email String @unique @db.VarChar(255)
name String? @db.VarChar(100)
posts Post[]
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
@@map("users") // Nombre personalizado de tabla
}
model Post {
id Int @id @default(autoincrement())
title String @db.VarChar(200)
content String? @db.Text
published Boolean @default(false)
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
authorId Int
tags Tag[]
createdAt DateTime @default(now())
@@map("posts")
}
model Tag {
id Int @id @default(autoincrement())
name String @unique @db.VarChar(50)
posts Post[]
@@map("tags")
}
Errores comunes
- No definir relaciones correctamente: Olvidar el campo
authorIden Post o no usar@relationcausa errores en migraciones. Siempre incluye ambos lados de la relación. - Validaciones insuficientes: Usar
Stringsin límites (como@db.VarChar(255)) puede llevar a datos excesivamente largos en producción. Especifica restricciones de base de datos. - Ignorar eliminación en cascada: En relaciones, no configurar
onDelete(ej:CascadeoSetNull) puede dejar datos huérfanos. Define el comportamiento según tu lógica de negocio. - No usar migraciones incrementalmente Hacer cambios grandes en el schema de una vez complica el rollback. Aplica migraciones pequeñas y frecuentes.
- Olvidar índices para rendimiento: En producción, campos usados frecuentemente en consultas (como
authorId) deben tener índices. Añade@@indexen modelos.
Checklist de dominio
- ¿Definiste todos los modelos necesarios para tu aplicación con campos tipados correctamente?
- ¿Estableciste relaciones (uno-a-muchos, muchos-a-muchos) usando
@relationy campos de clave foránea? - ¿Añadiste validaciones clave como
@unique,@default, y restricciones de base de datos (ej:@db.VarChar(255))? - ¿Configuraste comportamientos de eliminación (ej:
onDelete: Cascade) para mantener la integridad referencial? - ¿Usaste
@@mappara personalizar nombres de tablas si es necesario para convenciones de tu equipo? - ¿Consideraste añadir índices con
@@indexpara campos consultados frecuentemente? - ¿Probaste el schema generando una migración con
prisma migrate devy verificando que no haya errores?
Diseña un Schema para un Sistema de Reservas de Hotel
En este ejercicio, crearás un schema Prisma para un sistema de reservas de hotel en producción. Sigue estos pasos:
- Crea un nuevo proyecto Node.js e instala Prisma con
npm install prisma @prisma/client. - Inicializa Prisma con PostgreSQL:
npx prisma init. - En
schema.prisma, define los siguientes modelos con relaciones y validaciones:- Habitacion: id, numero (único), tipo (ej: 'individual', 'doble'), precioPorNoche, reservas (relación).
- Cliente: id, email (único), nombre, telefono, reservas (relación).
- Reserva: id, fechaEntrada, fechaSalida, total, cliente (relación), habitacion (relación).
- Añade validaciones: precioPorNoche debe ser positivo, email con formato, fechas válidas.
- Configura la relación entre Reserva y Habitacion como muchos-a-uno, y entre Reserva y Cliente como muchos-a-uno.
- Ejecuta
npx prisma migrate dev --name initpara generar y aplicar la migración. - Verifica que no haya errores y que las tablas se creen correctamente en tu base de datos.
Pistas
- Usa tipos como @db.Decimal para precioPorNoche para precisión en moneda.
- Considera añadir un campo @default(now()) para fecha de creación en Reserva.
- Para la relación, asegúrate de incluir habitacionId y clienteId en el modelo Reserva.
Evalua tu comprension
Completa el quiz interactivo de arriba para ganar XP.
Sigue con Prisma ORM Profesional: Schemas, Migraciones y Queries Optimizadas para Producción
Esta lección forma parte de un curso de Cursalo. Revisa su programa y elige entre la compra individual o el acceso a toda la escuela.
Si ya tenías acceso a este curso, entra con tu cuenta: tus derechos y tu progreso se conservan. No necesitas comprarlo de nuevo.