英文:
How to create association only if it doesn't exist? (GORM)
问题
我正在遍历一个字符串数组,只有在该属性不存在时才创建一个具有该属性的文档:
(dbi:我的 GORM 数据库实例)
var postTags []models.Tag
for _, tagSlug := range tagsArray {
tag := models.Tag{
Slug: tagSlug,
}
err = dbi.Where("slug = ?", tagSlug).FirstOrCreate(&tag).Error
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "Internal Server Error",
})
}
postTags = append(postTags, tag)
}
然后使用这些标签创建一个帖子:
post := models.Post{
...,
Tags: postTags
}
dbi.Create(&post)
模型:
type Post struct {
BaseModel
Title string `json:"title"`
MarkdownUploadURL string `json:"markdownUploadUrl"`
AuthorID string `json:"authorId"`
Tags []Tag `json:"tags" gorm:"many2many:posts_tags"`
}
type Tag struct {
BaseModel
Slug string `json:"slug"`
}
我尝试过:将 dbi.FirstOrCreate()
更改为 dbi.First()
,然后检查 errors.Is(err, gorm.ErrRecordNotFound)
。
但是,每次调用该函数时,即使它们已经存在于数据库中,我都会得到具有不同 ID 的不同标签...
英文:
I am looping through an array of strings to create an document with that property ONLY if it doesn't exist:
(dbi: my GORM database instance)
var postTags []models.Tag
for _, tagSlug := range tagsArray {
tag := models.Tag{
Slug: tagSlug,
}
err = dbi.Where("slug = ?", tagSlug).FirstOrCreate(&tag).Error
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
"error": "Internal Server Error",
})
}
postTags = append(postTags, tag)
}
And then Creating a post with those tags:
post := models.Post{
...,
Tags: postTags
}]
dbi.Create(&post)
Models:
type Post struct {
BaseModel
Title string `json:"title"`
MarkdownUploadURL string `json:"markdownUploadUrl"`
AuthorID string `json:"authorId"`
Tags []Tag `json:"tags" gorm:"many2many:posts_tags"`
}
type Tag struct {
BaseModel
Slug string `json:"slug"`
}
I tried: Changing dbi.FirstOrCreate()
for dbi.First()
and then checking if errors.Is(err, gorm.ErrRecordNotFound
But every time The function is called I get different Tags with different IDs, even if they already exist in the database...
答案1
得分: 0
据我理解,你可以以更精确和高效的方式实现你的目标。
- 在迭代
tagsArray
时,将主键(很可能是在你的BaseModel中)添加到你的标签中。 - 然后,将缺失的标签放入帖子中,而不是在数据库中创建它。
- 然后创建帖子(默认情况下,它将更新关联)。由于你在标签中提供了ID,这将与现有的ID冲突,并将使用先前的值进行更新(实际上什么也不做),否则将作为新标签插入,以防该ID没有对应的行。
var postTags []models.Tag
for _, tagSlug := range tagsArray {
tag := models.Tag{
ID: models.BaseModel{ ID: tagSlug.ID},
Slug: tagSlug,
}
postTags = append(postTags, tag)
}
post := models.Post{
...,
Tags: postTags
}
dbi.Create(&post)
请注意,这只是代码的一部分,可能需要根据你的实际情况进行适当的调整。
英文:
As far as I understand you can achieve your target in a more precise and efficient way.
- Add primary key (most probably in your BaseModel) to your tag when iterating
tagsArray
. - Then instead of creating the absent tags in db put it in post.
- Then create the Post (By default it will upsert associations). As you're giving ID in tag this will conflict with existing ID and will do update with previous values (essentially doing nothing) otherwise insert as new tag in case no row present for that ID.
var postTags []models.Tag
for _, tagSlug := range tagsArray {
tag := models.Tag{
ID: models.BaseModel{ ID: tagSlug.ID},
Slug: tagSlug,
}
postTags = append(postTags, tag)
}
post := models.Post{
...,
Tags: postTags
}]
dbi.Create(&post)
答案2
得分: 0
修复了。不是在帖子中添加标签,而是像这样进行操作:
post := models.Post{
Tags: postTags,
}
dbi.Create(&post)
我是这样做的:
post := models.Post {
// 其他字段 (AuthorID, MarkdownUploadURL, Title)
}
dbi.Create(&post)
dbi.Model(&post).Omit("Tags.*").Association("Tags").Append(postTags)
参考链接:https://github.com/go-gorm/gorm/issues/3605
英文:
Fixed it. Instead of addding the tags in the post, like so:
post := models.Post{
Tags: postTags,
}
dbi.Create(&post)
I did it like this:
post := models.Post {
// Other fields (AuthorID, MarkdownUploadURL, Title)
}
dbi.Create(&post)
dbi.Model(&post).Omit("Tags.*").Association("Tags").Append(postTags)
reference: https://github.com/go-gorm/gorm/issues/3605
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论