为结构找到 Gorm 无效字段

Gorm invalid field found for struct

我的数据库结构目标

one user can join many communities
and
one user can own a community

这是我想出的结构,正确吗?

type User struct {
    gorm.Model
    Communities []Community `gorm:"many2many:user_communities" json:"communities"`
    FirstName string `json:"firstName"`
    LastName string `json:"lastName"`
}

type Community struct {
    gorm.Model
    Name string `json:"name"`
    UserID uint `json:"userID"`
    Users []User `gorm:"many2many:user_communities" json:"users"`
}

这是我的数据库设置

func ConnectMysql() {
    // Connect to Mysql database based on the environment variable
    dsn := os.Getenv("MYSQL_DSN")

    database, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})

    if err != nil {
        panic("Failed to connect to the database")
    }

    database.AutoMigrate(&models.User{})
    database.AutoMigrate(&models.Community{})

    DB = database
}

以及如何查询以检查用户是否属于某个社区?

到目前为止我想到了这个但是它不起作用,可能我上面的架构是错误的

func CreateQuestion() {
    var community Community
    var foundUser User

    communityID = 1
    userID = 1

    // Find the community
    if err := database.Mysql.Where("id = ?", communityID).First(&community).Error; err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "Community does not exist"})
        return
    }
    
    // Im not sure whether this query is to check whether the user belongs to the community with id 1 or not.
    if err := database.Mysql.Preload("Community").Where("id = ?", userID).Find(&foundUser).Error; err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "user is not in the community"})
        return
    }
}

我得到的错误

[error] invalid field found for struct github.com/testing-be/Community's field Users: define a valid foreign key for relations or implement the Valuer/Scanner interface

也许您在结构中遗漏了 gorm.Model

type User struct {
    gorm.Model
    Communities []Community `json:"communities"`
    FirstName string `json:"firstName"`
    LastName string `json:"lastName"`
}

type Community struct {
    gorm.Model
    Name string `json:"name"`
    UserID uint `json:"userID"`
    Users []User `gorm:"many2many:user_communities" json:"users"`
}

https://gorm.io/docs/many_to_many.html

出现此错误的原因是 gorm 找不到定义关系的外键。

将 ID 字段添加到 UserCommunity 结构(或使用 gorm.Model 而不是 ID)。此外,还要为 Communities 字段添加 many2many

type User struct {
    ID uint `json:"id"`
    Communities []Community `gorm:"many2many:user_communities" json:"communities"`
    FirstName string `json:"firstName"`
    LastName string `json:"lastName"`
}

type Community struct {
    ID uint `json:"id"`
    Name string `json:"name"`
    UserID uint `json:"userID"`
    Users []User `gorm:"many2many:user_communities" json:"users"`
}

默认情况下,gorm 会尝试这样解析关系:

// Join Table: user_communities
//   foreign key: user_id, reference: users.id
//   foreign key: community_id, reference: communities.id

如果 user_communities table 中的外键名称不同,here 是您可以处理的方式。

关于Preload函数,它接受的是字段名,而不是字段类型,所以代码应该是这样的:

var foundUser User
    if err := database.Mysql.Preload("Communities").Where("id = ?", userID).First(&foundUser).Error; err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": "user is not in the community"})
        return
    }

此代码加载与找到的用户有关系的所有社区。

编辑:

以下示例可帮助您确定特定用户是否属于特定社区:

//Raw query
userID := 1
communityID := 1
var found sql.NullBool
if err := database.Mysql.Raw("SELECT 1 FROM users u JOIN user_communities uc ON u.id = uc.user_id WHERE u.id = ? AND uc.community_id = ?", userID, communityID).Scan(&found).Error; err != nil {
      c.JSON(http.StatusBadRequest, gin.H{"error": "error happened"})
            return
    }
if found.Valid && found.Bool {
  //user is part of the specified community
}

//With gorm functions
userID := 1
communityID := 1
var found sql.NullBool
if err := database.Mysql.Table("users u").Joins("JOIN user_communities uc ON u.id = uc.user_id").Where("u.id = ? AND uc.community_id = ?", userID, communityID).Select("1").Scan(&found).Error; err != nil {
      c.JSON(http.StatusBadRequest, gin.H{"error": "error happened"})
            return
    }
if found.Valid && found.Bool {
  //user is part of the specified community
}

接下来是如何加载指定用户和指定社区的示例:

//Finds just the specified user and loads just a specified community
userID := 1
communityID := 1
var user User
err := database.Mysql.Preload("Communities", "id = ?", communityID).Joins("JOIN user_communities uc ON u.id = uc.user_id").Where("uc.community_id = ?", communityID).First(&user, userID).Error
// err could be gorm.ErrorNotFound, which means that a record is not found, so this needs to be checked before err != nil check

//Finds just the specified user, loads all user's communities, but makes sure that a user belongs to a specific community
userID := 1
communityID := 1
var user User
err := database.Mysql.Preload("Communities").Joins("JOIN user_communities uc ON u.id = uc.user_id").Where("uc.community_id = ?", communityID).First(&user, userID).Error
// err could be gorm.ErrorNotFound, which means that a record is not found, so this needs to be checked before err != nil check