2016-04-06 17 views
1

Ich prüfe Go's GORM lib. Ich finde diese Lib besonders nützlich und, Schritt für Schritt, spiele ich mit immer komplizierteren Vorstellungen.Wie behandeln Kaskadenbetrieb mit GORM (Go)

Ich bin mit dem Problem der Kaskadierung Operation Management konfrontiert.

Bei bestimmten Problemen schlägt der Verfasser vor, die AfterDelete zu verwenden. Das Problem ist: in den After/BeforeDelete-Funktionen sind verschachtelte Elemente nicht vorhanden.

Hat jeder eine gute Möglichkeit, dies zu implementieren?

Hier ist mein Code (fast arbeiten, wenn jemand Gorm entdeckt):

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

Dank

Antwort

0

ich diese Lösung für die Reaktion auf mein Problem umgesetzt haben:

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 
} 

Für jeden "Item" Datei in meinem DB-Management, ich habe eine benutzerdefinierte Funktion DeleteCascade erstellt.

Ich hoffe, dass es helfen wird :)

0

Hallo leider mein Freund, mein Englisch

Kaskade Ausschluss auszuführen, müssen Sie den Fremdschlüssel zwischen den Tabellen hinzufügen.

Dies ist ein Beispiel, in dem ich den Aufgabenverlauf mit Aufgaben verknüpft habe. Wenn ich die Aufgabe lösche, löscht sie bereits den Verlauf.

Fremdschlüssel hinzufügen

// 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") 

Mein Beispiel:

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