Golang中db.Preload问题的解决方法

Golang中db.Preload问题的解决方法 你好,这是代码:

package services

import (
    "fmt"
    "gorm.io/gorm"
)

type Article struct {
    gorm.Model
    Title   string
    Content string
    UserID  uint
    User    User
}

type User struct {
    gorm.Model
    Name     string
    Email    string
    Articles []Article
}

func GetArticles(db *gorm.DB) ([]Article, error) {
    var articles []Article
    result := db.Preload("User").Find(&articles)
    if result.Error != nil {
        return nil, result.Error
    }
    return articles, nil
}

result := db.Preload("User").Find(&articles) 这行代码给我报错:"&{0xc0000fc2d0 User: unsupported relations for schema Article 2 0xc0002f8540 0}"。

你能帮我吗?


更多关于Golang中db.Preload问题的解决方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html

6 回复

谢谢。我决定在我的小型课程项目中使用SQL。

更多关于Golang中db.Preload问题的解决方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


感谢提供的链接,这让我很开心。如果我想了解更多信息,我会通过开启自己的主题来提问。

你好 Dean, 我提供的代码包含3个文件。分别是服务文件以及用户和文章模型。 我在文章中设置了外键,并且它工作正常。问题出现在使用 Preload 时。

这更像是一个关于Gorm的问题,而不是Go语言本身的问题。也就是说,文章没有关联的用户,所以Gorm不知道如何预加载用户。你可能需要在这些结构体/表之间定义一个关系:

GORM – 15 Mar 24

Has One

Has One关联在另一个模型之间建立了一对一的连接,但语义(和后果)略有不同。这种关联表示模型的每个实例都包含…

在这种情况下,也许文章有一个用户对象作为作者。另外,你为什么有多个版本的用户/文章结构体?最好统一它们。

你的 Article 结构体没有将 User 结构体作为一个属性。请参考我发布的链接以了解如何定义关联,以及这个关于预加载的文档页面:

GORM GORM – 15 Mar 24

预加载 (Eager Loading)

PreloadGORM 允许使用 Preload 在其他 SQL 中预加载关系,例如:

type User struct {
  gorm.Model
  Username string
  Orders   []Order
}
type Order struct {
  gorm.Model
  Use

你试图使用 db.Preload("User"),但你的 Article 结构体上没有要预加载的用户对象,因此出现了错误。你需要定义关联才能使其正常工作。

这个错误通常是因为GORM无法正确识别Article结构体中的User关联关系。问题可能出现在以下几个方面:

  1. 缺少外键标签:需要明确定义外键关系
  2. 关联方向问题:需要正确定义双向关联

以下是修正后的代码:

package services

import (
    "gorm.io/gorm"
)

type Article struct {
    gorm.Model
    Title   string
    Content string
    UserID  uint
    User    User `gorm:"foreignKey:UserID"`
}

type User struct {
    gorm.Model
    Name     string
    Email    string
    Articles []Article `gorm:"foreignKey:UserID"`
}

func GetArticles(db *gorm.DB) ([]Article, error) {
    var articles []Article
    result := db.Preload("User").Find(&articles)
    if result.Error != nil {
        return nil, result.Error
    }
    return articles, nil
}

如果问题仍然存在,可以尝试使用完整的关联配置:

type Article struct {
    gorm.Model
    Title   string
    Content string
    UserID  uint
    User    User `gorm:"foreignKey:UserID;references:ID"`
}

type User struct {
    gorm.Model
    Name     string
    Email    string
    Articles []Article `gorm:"foreignKey:UserID"`
}

另一个可能的解决方案是使用Preload的完整语法:

func GetArticles(db *gorm.DB) ([]Article, error) {
    var articles []Article
    result := db.Preload("User", func(db *gorm.DB) *gorm.DB {
        return db.Select("ID", "Name", "Email") // 明确指定要加载的字段
    }).Find(&articles)
    
    if result.Error != nil {
        return nil, result.Error
    }
    return articles, nil
}

如果使用的是GORM v2,还可以尝试初始化数据库连接时配置命名策略:

db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{
    NamingStrategy: schema.NamingStrategy{
        SingularTable: true,
    },
})

确保数据库表结构已经正确迁移:

db.AutoMigrate(&User{}, &Article{})
回到顶部