3

我正在测试 Go 的 GORM 库。我发现这个库特别有用,而且我一步一步地玩弄越来越复杂的概念。

我面临着级联运营管理的问题。

在某些问题上,创建者建议使用 AfterDelete。问题是:在 After/BeforeDelete 函数中,嵌套项不存在。

每个人都有实现这个的好方法吗?

这是我的代码(如果有人发现 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)
    }
}

谢谢

4

3 回答 3

5

要执行级联排除,您必须在表之间添加外键。

这是我使用的一个示例,其中任务历史记录与任务相关联。当我删除任务时,它已经删除了历史记录。

添加外键

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

我的例子:

db.Model(&models.TaskHistoric{}).AddForeignKey("task_uuid", "tasks(uuid)", "CASCADE", "CASCADE")
于 2017-01-11T18:16:51.180 回答
2
type Bucketlist struct {
    gorm.Model
    Name      string           `json:"name"`
    CreatedBy string           `json:"created_by"`
    UserID    uint             `json:"user_id"`
    Item      []BucketlistItem `json:"item"`
}

type BucketlistItem struct {
    gorm.Model
    Name         string `json:"name"`
    Done         bool   `json:"done"`
    BucketlistID uint   `json:"bucketlist_id,omitempty"`
}

// AfterDelete hook defined for cascade delete
func (bucketlist *Bucketlist) AfterDelete(tx *gorm.DB) error {
    return tx.Model(&BucketlistItem{}).Where("bucketlist_id = ?", bucketlist.ID).Unscoped().Delete(&BucketlistItem{}).Error
}

这对我有用

上下文:当一个bucketlist模型实例被删除时,相应的项目(1到x)也被使用AfterDelete钩子删除。

于 2019-08-13T17:53:51.370 回答
0

我已经实施了这个解决方案来解决我的问题:

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
}

对于我的数据库管理中的每个“项目”文件,我创建了一个自定义函数 DeleteCascade。

我希望它会有所帮助:)

于 2016-04-11T09:48:36.943 回答