3

Go の GORM ライブラリをテストしています。私はこのライブラリが特に便利だと思い、一歩一歩、ますます複雑な概念で遊んでいます。

カスケード運用管理の問題に直面しています。

特定の問題では、作成者は AfterDelete を使用することを提案しています。問題は、After/BeforeDelete 関数で、ネストされたアイテムが存在しないことです。

誰もがこれを実装する良い方法を持っていますか?

これが私のコードです(誰かがゴームを発見している場合、ほとんど機能しています):

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 に答える
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
}

DB 管理のすべての「アイテム」ファイルに対して、カスタム関数 DeleteCascade を作成しました。

私はそれが役立つことを願っています:)

于 2016-04-11T09:48:36.943 に答える