2016-04-06 2 views
1

Je teste la librairie GORM de Go. Je trouve cette lib particulièrement utile et, petit à petit, je joue avec des notions de plus en plus compliquées.Comment traiter le fonctionnement en cascade avec GORM (Go)

Je suis confronté au problème de la gestion des opérations en cascade.

Sur certains problèmes, le créateur suggère d'utiliser AfterDelete. Le problème est: dans les fonctions After/BeforeDelete, les éléments imbriqués ne sont pas présents.

Est-ce que tout le monde a un bon moyen de mettre en œuvre cela?

Voici mon code (travail presque si quelqu'un découvre Gorm):

package main 

import (
    "time" 
    "github.com/jinzhu/gorm" 
    _ "github.com/jinzhu/gorm/dialects/sqlite" 
    "fmt" 
    "github.com/satori/go.uuid" 
) 

type Company struct { 
    ID  string  `gorm:"primary_key;column:ID"` 
    Name  string  `sql:"size:255;unique;index" gorm:"column:Name"` 
    Employees []Employee // one-to-many relationship 
    Address Address // one-to-one relationship 
} 

func (u Company) TableName() string { 
    return "Company" 
} 
func (u Company) String() string { 
    return fmt.Sprintf("ID: %s | Name: %s | Employees: %v | Address: %v ", u.ID, u.Name, u.Employees, u.Address) 
} 
func (u *Company) BeforeCreate(scope *gorm.Scope) error { 
    scope.SetColumn("ID", uuid.NewV4().String()) 
    return nil 
} 
func (u *Company) BeforeDelete(scope *gorm.Scope) error { 
    fmt.Println("BeforeDelete") 
    fmt.Println(u) 
    return nil 
} 
func (u *Company) AfterDelete(scope *gorm.Scope) error { 
    fmt.Println("AfterDelete") 
    fmt.Println(u) 
    return nil 
} 

type Employee struct { 
    ID  string  `gorm:"primary_key;column:ID"` 
    FirstName  string `gorm:"column:FirstName"` 
    LastName   string `gorm:"column:LastName"` 
    SocialSecurityNo string `gorm:"column:SocialSecurityNo"` 
    DateOfBirth  time.Time `sql:"DEFAULT:current_timestamp" gorm:"column:DateOfBirth"` 
    Deleted   bool  `sql:"DEFAULT:false" gorm:"column:Deleted"` 
    CompanyID string `gorm:"column:Company_ID"` 
    Roles []Role // one-to-many relationship 
} 
func (u Employee) TableName() string { 
    return "Employee" 
} 
func (u Employee) String() string { 
    return fmt.Sprintf("ID: %s | FirstName: %s | Roles: %v ", u.ID, u.FirstName, u.Roles) 
} 
func (u *Employee) BeforeCreate(scope *gorm.Scope) error { 
    scope.SetColumn("ID", uuid.NewV4().String()) 
    return nil 
} 

type Role struct { 
    Name string `gorm:"column:Name"` 
    Code string `gorm:"column:Code"` 
    EmployeeID string `gorm:"column:Employee_ID"` 
} 
func (u Role) TableName() string { 
    return "Role" 
} 
func (u Role) String() string { 
    return fmt.Sprintf("Name: %s | Code: %s", u.Name, u.Code) 
} 

type Address struct { 
    Country string `gorm:"column:Country"` 
    City  string `gorm:"column:City"` 
    PostCode string `gorm:"column:PostCode"` 
    Line1 string `gorm:"column:Line1"` 
    Line2 string `gorm:"column:Line2"` 
    CompanyID string `gorm:"column:Company_ID"` 
} 
func (u Address) TableName() string { 
    return "Address" 
} 

func main() { 
    db := getDBConnection() 
    //If needed, you can create the file and schemas with the line below 
    createTables(db) 
    testCRUD(db) 
} 

func getDBConnection() (db *gorm.DB) { 
    //Change the file location for your needs 
    db, err := gorm.Open("sqlite3", `C:\Users\jbricout\Desktop\TestORM.db`) 
    if err != nil { 
     panic(err) 
    } 

    // Ping function checks the database connectivity 
    err = db.DB().Ping() 
    if err != nil { 
     panic(err) 
    } 

    return db 
} 

func createTables(db *gorm.DB) { 
    if err := db.CreateTable(&Company{}).Error; err != nil { 
     checkErr(err) 
    } 
    if err := db.CreateTable(&Address{}).Error; err != nil { 
     checkErr(err) 
    } 
    if err := db.CreateTable(&Employee{}).Error; err != nil { 
     checkErr(err) 
    } 
    if err := db.CreateTable(&Role{}).Error; err != nil { 
     checkErr(err) 
    } 
} 

func testCRUD(db *gorm.DB) { 
    sampleCompany := getInitializedCompany() 

    fmt.Println("Insert...") 
    if err := db.Create(&sampleCompany).Error; err != nil { 
     checkErr(err) 
    } 
    fmt.Println("Insert done with id : ", sampleCompany.ID) 

    fmt.Println("Find Only Company (Lazy load)...") 
    var firstComp Company 
    if err := db.Where("ID = ?", sampleCompany.ID).First(&firstComp).Error; err != nil { 
     checkErr(err) 
    } 
    fmt.Println("Company : ", firstComp) 
    fmt.Println("Find done") 

    fmt.Println("Find Only Company (Eager load)...") 
    var fullComp Company 

    db.Preload("Employees.Roles").Preload("Address").First(&fullComp) 
    if err := db.Where("ID = ?", sampleCompany.ID).First(&fullComp).Error; err != nil { 
     checkErr(err) 
    } 
    fmt.Println("Company : ", fullComp) 
    fmt.Println("Find done") 

    fmt.Println("Update...") 
    firstComp.Name = "Google Plus" 
    if len(firstComp.Address.Country) > 0 { 
     firstComp.Address.Country = "France" 
    } 

    if err := db.Save(&firstComp).Error; err != nil { 
     checkErr(err) 
    } 
    fmt.Println("Update done") 

    transaction := db.Begin() 
    fmt.Println("Delete...") 
    if err := transaction.Delete(&firstComp).Error; err != nil { 
     checkErrTransaction(err, transaction) 
    } 

    transaction.Commit() 
    fmt.Println("Delete done") 
} 

func getInitializedCompany() Company { 
    return Company{ 
     Name: "Google", 
     Address: Address{ 
      Country: "USA", 
      City:  "Moutain View", 
      PostCode: "1600", 
      Line1: "Cloverfield Lane, 32", 
      Line2: "Apt 64", 
     }, 
     Employees: []Employee{ 
      Employee{ 
       FirstName:  "John", 
       LastName:   "Doe", 
       SocialSecurityNo: "00-000-0000", 
       Roles: []Role{ 
        Role{ 
         Name: "Metier 1", 
         Code: "MET1", 
        }, 
        Role{ 
         Name: "Metier 2", 
         Code: "MET2", 
        }, 
       }, 
      }, 
      Employee{ 
       FirstName:  "James", 
       LastName:   "Dean", 
       SocialSecurityNo: "00-000-0001", 
       Roles: []Role{ 
        Role{ 
         Name: "Metier 1", 
         Code: "MET1", 
        }, 
       }, 
      }, 
      Employee{ 
       FirstName:  "Joan", 
       LastName:   "Dutsch", 
       SocialSecurityNo: "00-000-0002", 
       Roles: []Role{ 
        Role{ 
         Name: "Metier 2", 
         Code: "MET3", 
        }, 
       }, 
      }, 
     }, 
    } 
} 

func checkErr(err error) { 
    if err != nil { 
     panic(err) 
    } 
} 

func checkErrTransaction(err error, transaction *gorm.DB) { 
    transaction.Rollback() 
    if err != nil { 
     panic(err) 
    } 
} 

Merci

Répondre

0

J'ai mis en œuvre cette solution pour répondre à mon problème:

func DeleteContentCascade(content *Content, db *gorm.DB, debug bool) error { 

    if debug { 
     db = db.Debug() 
    } 

    for _, child := range content.Children { 
     DeleteChildCascade(&child, db, debug) //Custom method like the current 
    } 

    if err := db.Delete(content).Error; err != nil { 
     return err 
    } 

    return nil 
} 

Pour chaque "Item" Fichier dans ma gestion de base de données, j'ai créé une fonction personnalisée DeleteCascade.

J'espère que ça vous aidera :)

0

Bonjour mon ami désolé mon anglais

Pour effectuer l'exclusion en cascade, vous devez ajouter la clé étrangère entre les tables.

Cet exemple est utilisé lorsque l'historique des tâches est lié à des tâches. Lorsque je supprime la tâche, il supprime déjà l'historique.

Ajouter la clé étrangère

// Add foreign key 
// 1st param : foreignkey field 
// 2nd param : destination table(id) 
// 3rd param : ONDELETE 
// 4th param : ONUPDATE 
db.Model(&User{}).AddForeignKey("city_id", "cities(id)", "RESTRICT", "RESTRICT") 

Mon exemple:

db.Model(&models.TaskHistoric{}).AddForeignKey("task_uuid", "tasks(uuid)", "CASCADE", "CASCADE")