Gorm在结构体中找到无效字段。

huangapple go评论126阅读模式
英文:

Gorm invalid field found for struct

问题

我的数据库结构目标

一个用户可以加入多个社区
并且
一个用户可以拥有一个社区

这是我设计的结构,是否正确?

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() {
// 根据环境变量连接到 MySQL 数据库
dsn := os.Getenv("MYSQL_DSN")

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

if err != nil {
    panic("无法连接到数据库")
}

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

DB = database

}

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

到目前为止,我想到了以下代码,但它不起作用,可能是上面的模式有问题

func CreateQuestion() {
var community Community
var foundUser User

communityID = 1
userID = 1

// 查找社区
if err := database.Mysql.Where("id = ?", communityID).First(&community).Error; err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": "社区不存在"})
    return
}

// 我不确定这个查询是用来检查用户是否属于 ID 为 1 的社区。
if err := database.Mysql.Preload("Community").Where("id = ?", userID).Find(&foundUser).Error; err != nil {
    c.JSON(http.StatusBadRequest, gin.H{"error": "用户不在社区中"})
    return
}

}

我得到的错误信息

[error] 无效的字段 found for struct
github.com/testing-be/Community 的字段 Users:为关系定义一个有效的外键或实现 Valuer/Scanner 接口

英文:

My database structure goal

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

This is the structure that I came up with, is this correct?

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"`
}

This is my database setup

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
}

and how do I query to check whether a user belongs to a community?

So far I came up with this but it's not working, probably my schema above is wrong

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
	}
}

The error that I got

> [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

答案1

得分: 2

你得到这个错误的原因是gorm无法找到定义关系的外键。

UserCommunity结构体中添加ID字段(或者使用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表中的外键命名不同,你可以参考这里来处理。

关于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
}

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

编辑:

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

//原始查询

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 {
    //用户是指定社区的一部分
}

//使用gorm函数
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 {
    //用户是指定社区的一部分
}

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

//仅查找指定用户,并加载指定社区

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可能是gorm.ErrorNotFound,表示未找到记录,因此在err != nil之前需要检查这一点

//仅查找指定用户,加载所有用户的社区,但确保用户属于特定社区
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可能是gorm.ErrorNotFound,表示未找到记录,因此在err != nil之前需要检查这一点
英文:

The reason you got this error is that gorm cannot find the foreign key for the defined relationship.

Add the ID field to both User and Community structs (or use gorm.Model instead of the ID). Also, add many2many for the Communities field as well.

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"`
}

By default, gorm will try to resolve the relationship like this:

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

If your foreign keys in the user_communities table are named differently, here is how you could handle that.

Regarding the Preload function, it takes field names, not field types, so the code should be something like this:

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
    }

This code loads all the communities that have a relationship with the found user.

EDIT:

The following examples should help you to determine if a specific user belongs to a specific community:

//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
}

Next, the examples on how to load a specified user with a 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

答案2

得分: 0

也许你在结构体中错过了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

英文:

Perhaps you might have missed gorm.Model in your structs?

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

huangapple
  • 本文由 发表于 2022年2月5日 15:54:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/70996191.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定