Formation PUB900 : Développer une application pour iPhone avec SwiftUI, H-2024 CRUD avec SwiftData

42.2 Insérer ou supprimer des données d'une table enfant


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.

Suppression

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).

Fichier ContentView.swift

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 :

Fichier ListeItems.swift

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: {
                modelContext.delete(item) // 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.

Fichier ListeItems.swift

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)
}

Ajout

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 :

Swift

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.
  modelContext.insert(Item(...))
}) {
  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.

Swift

Button(action: {
  categorie.items.append(Item(...))
  do {
    try modelContext.save()
  } catch {
    print("Impossible d'ajouter l'item: \(error)")
  }
}) {
  Text("Enregistrer")
}

▼Publicité

Veuillez noter que le contenu de cette fiche vous est partagé à titre gracieux, au meilleur de mes connaissances et sans aucune garantie.
Merci de partager !
Soumettre