wandres.dev
SWIFTDATA · persistencia moderna

Relaciones y herencia de modelos

Conecta tus modelos con @Relationship, controla el borrado en cascada, y aprovecha la herencia de modelos, la gran novedad de SwiftData en 2026.

⏱ 13 min

Los datos reales no viven aislados: un proyecto tiene tareas, un usuario tiene pedidos, un álbum tiene fotos. SwiftData modela esas conexiones con @Relationship, y en 2026 suma algo muy pedido: la herencia de modelos.

🎯 Al terminar esta lección sabrás
  • Definir relaciones uno-a-muchos con @Relationship.
  • Controlar qué pasa al borrar (delete rules).
  • Relaciones inversas.
  • Herencia de modelos (novedad 2026).

Relaciones uno-a-muchos

Una relación es solo una propiedad que apunta a otro modelo (o a un array de ellos):

@Model
class Proyecto {
    var nombre: String
    @Relationship(deleteRule: .cascade) var tareas: [Tarea] = []
    init(nombre: String) { self.nombre = nombre }
}

@Model
class Tarea {
    var titulo: String
    var proyecto: Proyecto?      // el lado "muchos-a-uno"
    init(titulo: String) { self.titulo = titulo }
}

Añadir es tan simple como manipular el array: proyecto.tareas.append(tarea). SwiftData mantiene la conexión en la base de datos.

Delete rules: qué pasa al borrar

deleteRule controla el efecto de borrar el padre sobre los hijos:

🌊

.cascade

Borra los hijos también. Borrar un proyecto borra sus tareas. El más común.

🔒

.deny

Impide borrar el padre si tiene hijos. Protege contra borrados accidentales.

✂️

.nullify

Deja los hijos, pero rompe la relación (pone la referencia a nil). Por defecto.

💡
Elige la regla con intención

.cascade para composición fuerte (una tarea no tiene sentido sin su proyecto). .nullify cuando el hijo sobrevive por su cuenta (borrar una etiqueta no debería borrar los artículos etiquetados, solo quitarles la etiqueta). Pensar esto al modelar te ahorra datos huérfanos o borrados en cadena inesperados.

Herencia de modelos (novedad 2026)

La función más pedida y que por fin llegó este año: un @Model puede heredar de otro. Útil cuando varios tipos comparten campos comunes:

@Model
class Elemento {
    var titulo: String
    var creado: Date
    init(titulo: String) { self.titulo = titulo; self.creado = .now }
}

@Model
class Nota: Elemento {
    var contenido: String = ""
}

@Model
class Recordatorio: Elemento {
    var fecha: Date = .now
    var completado = false
}

Ahora puedes consultar todos los Elemento (y obtener notas y recordatorios juntos) o cada subtipo por separado. Comparten los campos base sin duplicarlos.

Modela el dominio, no la base de datos

La herencia de modelos te deja expresar jerarquías naturales de tu dominio (“todo es un Elemento con título y fecha, pero unos son notas y otros recordatorios”) directamente en el almacén, sin trucos ni tablas duplicadas. Combínalo con lo del Nivel 1: aquí las clases y la herencia sí tienen su lugar, porque estás modelando entidades persistentes con identidad. SwiftData 2026 hace que la capa de datos se parezca cada vez más a cómo piensas el problema, no a cómo lo guarda SQLite.

⚔️ Conecta tus datos
  1. Crea un Proyecto con una relación @Relationship(deleteRule: .cascade) a [Tarea].
  2. Añade tareas a un proyecto con .append y muéstralas.
  3. Borra el proyecto y comprueba que sus tareas también desaparecen (cascade).
  4. Crea un modelo base Elemento y dos subclases que hereden de él.
  5. Consulta todos los Elemento y observa que trae ambos subtipos.