Saltar al contenidoPedro Farbo
Lección 11 / 2550 min

Relaciones en Base de Datos

Relaciones en Base de Datos

Vamos a modelar las relaciones complejas del e-commerce con Prisma.

Schema Completo

prisma
// prisma/schema.prismamodel User {  id        String   @id @default(uuid())  email     String   @unique  name      String  password  String  role      Role     @default(USER)  orders    Order[]  reviews   Review[]  addresses Address[]  createdAt DateTime @default(now())  updatedAt DateTime @updatedAt} model Product {  id          String      @id @default(uuid())  name        String  slug        String      @unique  description String?  price       Decimal     @db.Decimal(10, 2)  stock       Int         @default(0)  images      String[]  category    Category    @relation(fields: [categoryId], references: [id])  categoryId  String  orderItems  OrderItem[]  reviews     Review[]  createdAt   DateTime    @default(now())  updatedAt   DateTime    @updatedAt   @@index([categoryId])} model Category {  id       String    @id @default(uuid())  name     String    @unique  slug     String    @unique  products Product[]} model Order {  id        String      @id @default(uuid())  user      User        @relation(fields: [userId], references: [id])  userId    String  items     OrderItem[]  address   Address     @relation(fields: [addressId], references: [id])  addressId String  total     Decimal     @db.Decimal(10, 2)  status    OrderStatus @default(PENDING)  createdAt DateTime    @default(now())  updatedAt DateTime    @updatedAt   @@index([userId])} model OrderItem {  id        String  @id @default(uuid())  order     Order   @relation(fields: [orderId], references: [id], onDelete: Cascade)  orderId   String  product   Product @relation(fields: [productId], references: [id])  productId String  quantity  Int  price     Decimal @db.Decimal(10, 2)   @@unique([orderId, productId])} model Review {  id        String   @id @default(uuid())  rating    Int  comment   String?  user      User     @relation(fields: [userId], references: [id])  userId    String  product   Product  @relation(fields: [productId], references: [id])  productId String  createdAt DateTime @default(now())   @@unique([userId, productId])} model Address {  id      String  @id @default(uuid())  user    User    @relation(fields: [userId], references: [id])  userId  String  street  String  city    String  state   String  zipCode String  country String  orders  Order[]} enum Role {  USER  ADMIN} enum OrderStatus {  PENDING  PAID  SHIPPED  DELIVERED  CANCELLED}

Consultas con Relaciones

typescript
// Pedido con todos los itemsconst order = await prisma.order.findUnique({  where: { id: orderId },  include: {    items: {      include: { product: true }    },    user: {      select: { id: true, name: true, email: true }    },    address: true,  },}); // Productos con promedio de reviewsconst products = await prisma.product.findMany({  include: {    reviews: true,    _count: { select: { reviews: true } },  },});

Transacciones

typescript
// Crear pedido (transacción)const order = await prisma.$transaction(async (tx) => {  // Verificar stock  for (const item of items) {    const product = await tx.product.findUnique({      where: { id: item.productId },    });     if (!product || product.stock < item.quantity) {      throw new AppError(`Sin stock: ${product?.name}`);    }  }   // Crear pedido  const order = await tx.order.create({    data: {      userId,      addressId,      total: calculateTotal(items),      items: {        create: items.map(item => ({          productId: item.productId,          quantity: item.quantity,          price: item.price,        })),      },    },  });   // Actualizar stock  for (const item of items) {    await tx.product.update({      where: { id: item.productId },      data: { stock: { decrement: item.quantity } },    });  }   return order;});

Resumen

  • ✅ Relaciones Uno-a-Muchos y Muchos-a-Muchos
  • ✅ Índices para rendimiento
  • ✅ Consultas anidadas
  • ✅ Transacciones para integridad

Próxima clase: Autenticación JWT! 🚀

¿Te gustó el contenido? ¡Tu contribución ayuda a mantener todo online y gratuito!

PIX:0737160d-e98f-4a65-8392-5dba70e7ff3e