指定'gorm:“unique”',导致的预加载属于关系问题

hwamh0ep  于 2022-12-07  发布在  Go
关注(0)|答案(1)|浏览(291)

下面是我的Post & User结构模型:

type Post struct {
    ID     string `gorm:"primaryKey"`
    Title  string `gorm:"unique"`
    UserID string
    User   User
}

type User struct {
    ID   string `gorm:"primaryKey"`
    Name string
}

// Code to create a Post with title & user input
func CreatePost(title string, u User) (Post, error) {
    b := Post{Title: title, User: u}
    dbIns := GetDB()
    if err := dbIns.Create(&b).Error; err != nil {
        return Post{}, err
    }
    return b, nil
}

// Code to get a Post, also preload its User field
func GetOnePost() (Post, error) {
    var p Post
    dbIns := GetDB()
    if err := dbIns.Model(&Post{}).Preload("User").First(&p).Error; err != nil {
        return Post{}, err
    }
    return p, nil
}

这是我从GetOnePost()得到的输出,这正是我所期望的,Post.User不是空的。

2022/11/27 15:42:48 Post title: John-Doe's Title, UUID: 32158510-6dcc-4c26-bcb8-7d76a88bda72, authorUUID: 73d020d3-eb8d-4bf7-9f57-e821c5deceed 
2022/11/27 15:42:48 User name: John-Doe, UUID: 73d020d3-eb8d-4bf7-9f57-e821c5deceed

但是当我指定User.Name是唯一的(因为我希望每个用户都有不同的Name)
注意:是,我确实迁移到了一个新表中。

type User struct {
    ID   string `gorm:"primaryKey"`
    Name string `gorm:"unique"`
}

GetOnePost()的输出更改为:(请忽略UUID)

2022/11/27 15:57:49 Post title: John-Doe's Title, UUID: 26355816-c376-497a-a250-be118c5933e2, authorUUID: e858cd72-56b9-4884-b6e6-94121c36719b 
2022/11/27 15:57:49 User name: , UUID:

一个问题是,返回的Post.User似乎是空的,当我向User模型添加唯一约束时。
如果我从User模型中删除unique约束,它就会恢复正常(Post.User非空)。所以在我看来,问题出在gorm:“unique”部分。

mec1mxoz

mec1mxoz1#

老实说,我无法重现您的问题。无论如何,我添加了我的尝试,以重现您的问题,如预期的那样工作。让我先显示代码,然后我会为您提供一个简短的解释:

package main

import (
    "fmt"

    "gorm.io/driver/postgres"
    "gorm.io/gorm"

    "github.com/google/uuid"
    _ "github.com/lib/pq"
)

type Post struct {
    ID     string `gorm:"primaryKey"`
    Title  string `gorm:"unique"`
    UserID string
    User   User
}

type User struct {
    ID   string `gorm:"primaryKey"`
    Name string `gorm:"unique"`
}

// Code to create a Post with title & user input
func CreatePost(db *gorm.DB, title string, u User) (Post, error) {
    id := uuid.NewString()
    b := Post{ID: id, Title: title, User: u}
    if err := db.Create(&b).Error; err != nil {
        return Post{}, err
    }
    return b, nil
}

// Code to get a Post, also preload its User field
func GetOnePost(db *gorm.DB) (Post, error) {
    var p Post
    if err := db.Model(&Post{}).Preload("User").First(&p).Error; err != nil {
        return Post{}, err
    }
    return p, nil
}

func main() {
    dsn := "host=localhost user=postgres password=postgres dbname=postgres port=5432 sslmode=disable"
    db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
    if err != nil {
        panic(err)
    }

    db.AutoMigrate(&User{})
    db.AutoMigrate(&Post{})

    defer db.Exec("DROP TABLE users")
    defer db.Exec("DROP TABLE posts")

    userId := uuid.NewString()

    _, err = CreatePost(db, "Learn Go", User{
        ID:   userId,
        Name: "John Doe",
    })
    if err != nil {
        panic(err)
    }

    post, err := GetOnePost(db)
    if err != nil {
        panic(err)
    }

    // this leads to a Duplicate error SQLSTATE 23505 in DB
    // if err := db.Create(&User{
    //  ID:   uuid.NewString(),
    //  Name: "John Doe",
    // }).Error; err != nil {
    //  panic(err)
    // }

    fmt.Printf("post's details: %v\n", post)
}

代码和您提供的差不多。我添加了两个延迟的函数调用,以便在每次运行代码后删除表。由于这一点,我们总是可以确保使用提供的最新表定义。然后,我在Postgres中检查UNIQUE约束是否存在,并且我正确地找到了它。然而,当我尝试运行我的代码时,我也成功地检索到了User信息。如果你试图取消注解以// this leads to a Duplicate error SQLSTATE 23505 in DB开头的代码块,你会得到一个重复的错误,所以约束是在数据库端强制执行的。
让我知道如果使用我的解决方案,你的代码也工作!

相关问题