Lorsqu'une requête SwiftData implique une table parent et une table enfant, par exemple des catégories avec, pour chacune, des items, les opérations sur la table enfant doivent être réalisées par manipulation de la variable initialisée par @Query et non à partir du modelContext.
En effet, si vous travaillez avec modelContext pour ajouter ou supprimer un élément dans la table enfant, les modifications ne seront pas immédiatement reflétées dans la vue parent puisque la variable initialisée par @Query ne sera pas mise à jour.
Note : la technique que je vous présente ici doit être utilisée lorsque les données de la table parent sont retrouvées par @Query et qu'on désire modifier les données de la table enfant.
Si c'est la table enfant qui est initialisée avec @Query, on travaillera directement avec modelContext.
Dans cet exemple, on travaille avec une vue qui affiche les catégories et, pour chacune, un lien qui permet d'afficher les items de la catégorie.
La requête va donc chercher les données de la table parent (categories), ce qui donne accès aux données de la table enfant (items).
struct ContentView: View {
@Query(sort: \Categorie.titre) var categories: [Categorie]
var body: some View {
...
List (categories) { categorie in
NavigationLink(value: categorie) {
Text(categorie.titre)
}
}
.navigationDestination(for: Categorie.self) { categorie in
ListeItems(categorie: categorie)
}
...
}
}
Si on veut, pour une catégorie donnée, supprimer un des items, il ne faut pas procéder comme suit :
struct ListeItems: View {
var categorie: Categorie
var body: some View {
VStack {
List (categorie.items.sorted(by: {$0.code < $1.code})) { item in
HStack {
Text("\(item.code) - \(item.titre)")
Spacer()
Button(
role: .destructive,
action: {
// ceci ne met pas à jour la vue qui a fait le @Query
}) {
Image(systemName: "trash")
.padding(.leading)
}
}
}
...
}
}
}
Il faut plutôt faire ceci, ce qui mettra à jour la variable initialisée par @Query.
SwiftData comprendra qu'il doit supprimer un item de la base de données.
Button(
role: .destructive,
action: {
// ici, on recherche dans un tableau d'items l'élément qui correspond à l'item sur leqel on vient de cliquer
if let index = categorie.items.firstIndex(where: {$0.persistentModelID == item.persistentModelID}) {
categorie.items.remove(at: index)
do {
try modelContext.save()
} catch {
print("Impossible de supprimer l'item: \(error)")
}
}
}) {
Image(systemName: "trash")
.padding(.leading)
}
Dans cet exemple, un tableau de catégories (table parent) a été initialisé à l'aide de @Query.
À un endroit donné dans l'application, un bouton permet d'ajouter un item dans une catégorie donnée.
Pour ajouter un enregistrement dans la table enfant, il ne faut pas procéder comme suit :
Button(action: {
// ceci ne sera visible que lors du prochain chargement de l'application puisque la modification n'affecte pas directement la variable initialisée par @Query.
}) {
Text("Enregistrer")
}
Il faut plutôt manipuler la propriété qui réfère à la table enfant. SwiftData comprendra qu'il doit insérer un enregistrement dans la table enfant.
Button(action: {
categorie.items.append(Item(...))
do {
try modelContext.save()
} catch {
print("Impossible d'ajouter l'item: \(error)")
}
}) {
Text("Enregistrer")
}
▼Publicité