2017-09-15 4 views
0

J'ai un modèle hiérarchique dans ma base de données (une équipe a des clients et chaque client peut avoir des notes). Mon objectif serait de pouvoir nettoyer la base de données si une équipe est supprimée: -> supprimer l'équipe -> supprimer tous les clients -> supprimer toutes les notes pour chaque clientGo-gorm BeforeDelete callback n'est pas appelé si delete est démarré dans un autre callback

Mon plan était de le faire avec le rappel BeforeDelete, mais après le callback de l'équipe, le BeforeDelete pour les clients n'est plus appelé correctement. Dans la base de données, l'équipe est supprimée ainsi que ses clients, mais pas les notes pour les clients. La ligne de journal n'est pas imprimée non plus. Savez-vous s'il est possible d'enchaîner ces rappels ou si c'est par conception que le second rappel n'est pas effectué?

package main 

import (
    "errors" 
    "log" 
    "github.com/jinzhu/gorm" 
    _ "github.com/jinzhu/gorm/dialects/sqlite" 
) 

var DB *gorm.DB 

type Team struct { 
    gorm.Model 
    Name  string 
    Customers []Customer 
} 

type Note struct { 
    gorm.Model 
    Content string 
    OwnerID uint 
    OwnerType string 
} 

type Customer struct { 
    gorm.Model 
    Name string 
    TeamID uint 
    Notes []Note `gorm:"polymorphic:Owner;"` 
} 

func (team *Team) BeforeDelete(tx *gorm.DB) (err error) { 
    log.Println("------- delete team ---------") 
    tx.Where("team_id = ?", team.ID).Delete(&Customer{}) 
    return 
} 

func (customer *Customer) BeforeDelete(tx *gorm.DB) (err error) { 
    log.Println("------- delete customer ---------") 
    tx.Where("owner_type = ? AND owner_id = ?", "customers", customer.ID).Delete(&Note{}) 
    return 
} 

func (note *Note) BeforeDelete(tx *gorm.DB) (err error) { 
    log.Println("------- delete note ---------") 
    return 
} 

func init() { 
    var err error 
    DB, err = gorm.Open("sqlite3", "data.DB") 

    if err != nil { 
     log.Printf("Error from gorm.Open: %s\n", err) 
    } 

    log.Println("You connected to your database.") 

    if DB.HasTable(&Team{}) { 
     DB.DropTable(&Team{}) 
     DB.DropTable(&Customer{}) 
     DB.DropTable(&Note{}) 
    } 

    if !DB.HasTable(&Team{}) { 
     DB.CreateTable(&Team{}) 
    } 
    if !DB.HasTable(&Customer{}) { 
     DB.CreateTable(&Customer{}) 
    } 
    if !DB.HasTable(&Note{}) { 
     DB.CreateTable(&Note{}) 
    } 
} 

func createTeam(name string) Team { 
    team := Team{Name: name} 
    DB.Create(&team) 
    return team 
} 

func addCustomer(teamID uint, name string) Customer { 
    customer1 := Customer{Name: name} 
    customer1.TeamID = teamID 
    customer1.Notes = []Note{} 
    DB.Create(&customer1) 
    return customer1 
} 

    func addNoteToCustomer(customerID uint, note Note) (customer Customer, err error) { 
    if DB.Preload("Notes").First(&customer, customerID).RecordNotFound() { 
    return customer, errors.New("customer doesn't exists") 
    } 

    customer.Notes = append(customer.Notes, note) 
    DB.Save(&customer) 
    return customer, err 
} 

func main() { 
    team := createTeam("Team 1") 
    team2 := createTeam("Team 2") 
    // Create customers 

    customer1 := addCustomer(team.ID, "TestC 1") 
    customer2 := addCustomer(team.ID, "TestC 2") 
    customer3 := addCustomer(team2.ID, "TestC 3") 
    customer4 := addCustomer(team2.ID, "TestC 4") 

    note1 := Note{Content: "testcontent"} 
    addNoteToCustomer(customer1.ID, note1) 
    note2 := Note{Content: "testcontent 2"} 
    addNoteToCustomer(customer2.ID, note2) 
    note3 := Note{Content: "testcontent 3"} 
    addNoteToCustomer(customer3.ID, note3) 
    note4 := Note{Content: "testcontent 4"} 
    addNoteToCustomer(customer4.ID, note4) 

    DB.Delete(&team) 
} 

Répondre

0

Après avoir essayé autour de beaucoup, j'ai trouvé une solution:

func (team *Team) BeforeDelete(tx *gorm.DB) (err error) { 
    //tx.Where("team_id = ?", team.ID).Delete(Customer{}) 
    var customers []Customer 
    tx.Model(&team).Related(&customers) 

    for _, customer := range customers { 
     tx.Delete(&customer) 
    } 
    return 
} 

Et de même pour les autres modèles. Si quelqu'un a une meilleure suggestion, je suis heureux de le lire (en quelque sorte je n'aime pas celui-ci - trop de code pour cela)

+0

Cela fonctionne comme prévu, mais je ne peux pas comprendre la différence majeure, pourquoi est-ce mieux que celui de la question. Si quelqu'un peut le signaler, je suis également content. Merci. – phev8

0

Je pense que c'est parce que la fonction BeforeDelete est ajoutée au pointeur du modèle client struct.

Vous venez de passer dans Customer{} dans votre premier exemple, qui n'est pas un pointeur vers la structure du modèle. Essayez l'exemple ci-dessous à la place?

var customer Customer 
func (team *Team) BeforeDelete(tx *gorm.DB) (err error) { 
    tx.Where("team_id = ?", team.ID).Delete(&customer) 
    return 
} 
+0

Merci pour votre réponse. A la première ligne ('' client var Customer {} "), j'obtiens une erreur de syntaxe, donc j'ai enlevé les accolades, mais malheureusement, cela ne résout pas non plus le problème original. symbole de référence dans l'exemple.Mais même si je le fais, l'équipe est supprimée et ses clients, mais pas les notes du client Je vais essayer d'ajouter le script entier à la question, de sorte que n'importe qui peut tester le comportement – phev8

+0

Cela semble toujours vrai, même en 2017. Je suis surpris par ce comportement, il serait trop facile pour quelqu'un d'exécuter 'db.Delete (Customer {...})' au lieu de 'db.Delete (& Customer {... {) '. Bien qu'il semble y avoir au moins une tentative de toujours appeler des méthodes sur le type de pointeur: https://github.com/jinzhu/gorm/commit/5174cc5c242a728b435ea2be8a2f7f998e15429b –