SwiftData est capable de gérer les relations entre deux tables.
Il se charge de créer les clés étrangères requises mais il ne crée pas de contraintes d'intégrité référentielle dans la base de données car il gère lui-même l'intégrité des données via son modèle objet.
Pour que le tout fonctionne, il faut apporter des ajustements aux modèles des tables parent et enfant.
Le modèle de la table parent aura une référence au modèle de la table enfant. Dans le contexte d'une relation de un à plusieurs, il s'agira d'un tableau.
Pour que SwiftData puisse établir la relation, il faut initialiser le tableau dès sa déclaration.
@Model
final class Categorie {
var titre: String
var items: [Item] = []
// Ce constructeur avec paramètre pour la liste d'items est requis si on veut insérer des données initiales.
// Puisque le paramètre a une valeur par défaut, il sera tout de même possible de créer une catégorie qui ne contient aucun item.
init(titre: String = "", items: [Item] = []) {
self.titre = titre
self.items = items
}
}
Le modèle de la table enfant doit avoir une référence au modèle de la table parent.
Pour que SwiftData puisse faire correctement le lien entre la table parent et la table enfant, cette propriété doit être un optionnel, c'est-à-dire qu'elle peut avoir la valeur nil, tel qu'indiqué par le point d'interrogation.
@Model
final class Item {
var code: String
var titre: String
var categorie: Categorie?
// Ce constructeur sans paramètre pour la clé étrangère est requis si on veut insérer des données initiales.
init(code: String = "", titre: String = "") {
self.code = code
self.titre = titre
}
init(code: String = "", titre: String = "", categorie: Categorie) {
self.code = code
self.titre = titre
self.categorie = categorie
}
}
Puisqu'il y a une relation entre les deux modèles, le ModelContainer n'a besoin que du nom d'une des classes. Il sera capable de retrouver l'autre par lui-même.
@main
struct MonProjetApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(for: Item.self)
}
}
Il est conseillé d'ajouter la macro @Relationship dans la table parent afin de rendre la relation explicite.
De plus, ceci permettre d'indiquer clairement ce qui se passera avec les enregistrements de la table enfant si un enregistrement de la table parent est supprimé.
La macro sera placée sur la même ligne ou au-dessus du tableau d'items.
Dans cet exemple, si on détruit une catégorie, tous les items de cette catégorie se verront attribuer la valeur nil dans la propriété categorie.
@Model
final class Categorie {
var titre: String
@Relationship(deleteRule: .nullify, inverse: \Item.categorie)
var items: [Item] = []
...
}
Dans cet exemple, si on détruit une catégorie, tous les items de cette catégorie seront également supprimés
@Model
final class Categorie {
var titre: String
@Relationship(deleteRule: .cascade, inverse: \Item.categorie)
var items: [Item] = []
...
}
Dans les premières versions de SwiftData, il fallait prendre des précautions supplémentaires pour que les relations entre les tables soient correctement gérées.
Les précautions qui suivent ne sont plus nécessaires, bien qu'elles ne nuisent pas au bon fonctionnement de l'application.
Dans le modèle de la table parent, la référence au modèle de la table enfant devait pouvoir prendre la valeur nil.
@Model
final class Categorie {
var titre: String
var items: [Item]? = [] // aujourd'hui, le tableau n'a plus besoin d'être un optionnel
...
}
Dans le modèle de la table parent, le tableau de modèles de la table enfant devait être assigné en dernier pour que la relation soit correctement établie entre les tables.
@Model
final class Categorie {
var titre: String
var items: [Item]? = []
init(titre: String = "", items: [Item] = []) {
self.titre = titre
self.items = items // cette ligne n'a plus besoin d'être exécutée en dernier
}
}
« Defining data relationships with enumerations and model classes ». Apple. https://developer.apple.com/documentation/swiftdata/defining-data-relationships-with-enumerations-and-model-classes/
« The Ultimate Guide to Building SwiftData Applications - Relationships ». AzamSharp. https://azamsharp.com/2023/07/04/the-ultimate-swift-data-guide.html#relationships
« Inferred vs explicit relationships ». Hacking with Swift. https://www.hackingwithswift.com/quick-start/swiftdata/inferred-vs-explicit-relationships
▼Publicité