英文:
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无法找到定义关系的外键。
在User
和Community
结构体中添加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"`
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论