gorm 中的外键约束

我想创建一个预订-舱位关系,在这个关系中,每个预订只能分配一个舱位。


type Class struct {

    Id   int    `json:"id"`

    Name string `json:"name"`

}


type Booking struct {

    Id      int    `json:"id"`

    User    string `json:"user"`

    Members int    `json:"members"`

    ClassId int    `json:"classid"`

}

我知道它类似于gorm在这里解释的“属于”关系,https://gorm.io/docs/belongs_to.html 但我想知道是否有可能在不定义Booking模型中的Class类型字段的情况下实现“外键约束”(只有ClassId int)。为了确保使用不存在的 ClassId-s,我定义了函数:


func Find(slice []int, val int) bool {

    for _, item := range slice {

        if item == val {

            return true

        }

    }

    return false

}


func GetClassKeys(d *gorm.DB) []int {


    var keys []int

    rows, _ := d.Raw(`SELECT id

                        FROM classes`).Rows()

    defer rows.Close()

    for rows.Next() {

        var key int

        rows.Scan(&key)

        keys = append(keys, key)

    }

    return keys

}

并在创建/更新预订之前执行此检查:


if !Find(GetClassKeys(db), booking.ClassId) {

    log.Println("Wrong class id value")

    return

}

但这不能处理删除类id的情况(常规数据库会自动执行此操作)。我想知道有没有办法通过简单地在用户模型中引用Class的主键来实现与gorm的正常数据库外键功能?提前致谢


噜噜哒
浏览 195回答 1
1回答

喵喔喔

我不认为迁移器工具会帮助你,因为它假设你将使用默认的Gorm模式来定义关系,并且你已经明确决定不使用这些模式。剩下的唯一选择是自己管理约束,要么通过SQL脚本,要么通过更简单的,在调用旁边运行的一些自定义查询:AutoMigrateimport "gorm.io/gorm/clause"// somewhere you must be callingdb.AutoMigrate(&Class{}, &Booking{})// then you'd have:constraint := "fk_booking_classid"var count int64err := db.Raw(    "SELECT count(*) FROM INFORMATION_SCHEMA.table_constraints WHERE constraint_schema = ? AND table_name = ? AND constraint_name = ?",     db.Migrator().CurrentDatabase(),    "bookings",    constraint,).Scan(&count).Error// handle errorif (count == 0) {    err := db.Exec(        "ALTER TABLE bookings ADD CONSTRAINT ? FOREIGN KEY class_id REFERENCES classes(id)",        clause.Table{Name: constraint},    ).Error    // handle error}当然,这否定了自动迁移的优势(这意味着当字段名称等内容发生变化时,约束将在不更改迁移代码的情况下更新)。我会看看为什么你不想像gorm预期的那样定义外键,因为这闻起来像你试图直接使用数据库模型作为JSON API请求/响应模型,这通常不会导致一个好的结束:)
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Go