Gorm:无法添加或更新子行 – 自引用的外键约束失败

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

Gorm: Cannot add or update a child row - a foreign key constraint fails on self referencing

问题

我有一个结构体,看起来像这样:

type Category struct {
    Code           *int      `gorm:"unique;primaryKey;"`
    ParentCategory *Category `gorm:"foreignKey:Code"`
}

一个 Category 可以有一个来自类型为 CategoryParentCategory。所以它引用了自身。
如果是第一个 Category,它没有 ParentCategory。

我有一个包含4个 Category 的数组,如上所述,第一个没有 ParentCategory。

当我逐个保存这些 Category(从第一个没有 ParentCategory 的开始),我得到以下错误(这里只打印前两个):

Error 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`ps_product_service`.`categories`, CONSTRAINT `fk_categories_parent_category` FOREIGN KEY (`code`) REFERENCES `categories` (`code`))
[20.890ms] [rows:0] INSERT INTO `categories` (`code`) VALUES (0) RETURNING `code`
Error when creating category: Error 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`ps_product_service`.`categories`, CONSTRAINT `fk_categories_parent_category` FOREIGN KEY (`code`) REFERENCES `categories` (`code`))&{Code:0x140003c6a00 ParentCategory:<nil>}
2023/06/19 21:31:44 Error 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`ps_product_service`.`categories`, CONSTRAINT `fk_categories_parent_category` FOREIGN KEY (`code`) REFERENCES `categories` (`code`))
[7.689ms] [rows:0] INSERT INTO `categories` (`code`) VALUES (99) RETURNING `code`
Error when creating category: Error 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`ps_product_service`.`categories`, CONSTRAINT `fk_categories_parent_category` FOREIGN KEY (`code`) REFERENCES `categories` (`code`))&{Code:0x140003c6a20 ParentCategory:<nil>}

我真的搞不清楚我在这里该怎么做。有人可以帮我吗?

英文:

I have a struct which looks like this:

type Category struct {
	Code           *int      `gorm:"unique;primaryKey;"`
	ParentCategory *Category `gorm:"foreignKey:Code"`
}

A Category itself can have a ParentCategory which is also from type Category. So it references to itself.
If its the first Category it has NO ParentCategory.

I have an array whith 4 Categories, as said, the first one doesnt have ab ParentCategory.

When saving these Categories one after one (Beginning with the first which has NO ParentCategory, I get these errors (Just print here the first two):

Error 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`ps_product_service`.`categories`, CONSTRAINT `fk_categories_parent_category` FOREIGN KEY (`code`) REFERENCES `categories` (`code`))
[20.890ms] [rows:0] INSERT INTO `categories` (`code`) VALUES (0) RETURNING `code`
Error when creating category: Error 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`ps_product_service`.`categories`, CONSTRAINT `fk_categories_parent_category` FOREIGN KEY (`code`) REFERENCES `categories` (`code`))&{Code:0x140003c6a00 ParentCategory:<nil>}
2023/06/19 21:31:44 Error 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`ps_product_service`.`categories`, CONSTRAINT `fk_categories_parent_category` FOREIGN KEY (`code`) REFERENCES `categories` (`code`))
[7.689ms] [rows:0] INSERT INTO `categories` (`code`) VALUES (99) RETURNING `code`
Error when creating category: Error 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`ps_product_service`.`categories`, CONSTRAINT `fk_categories_parent_category` FOREIGN KEY (`code`) REFERENCES `categories` (`code`))&{Code:0x140003c6a20 ParentCategory:<nil>}

I really cant figure out what I have to do here. Could someone help me with this please?

答案1

得分: 0

我应该使用以下代码来管理您的需求:

package main

import (
	"fmt"

	"github.com/samber/lo"
	"gorm.io/driver/postgres"
	"gorm.io/gorm"
)

type category struct {
	Code             uint     `gorm:"unique;primaryKey;"`
	ParentCategoryId *uint
	ParentCategory   *category `gorm:"foreignKey:ParentCategoryId"`
}

func main() {
	dsn := "host=localhost port=54322 user=postgres password=postgres dbname=postgres sslmode=disable"
	db, err := gorm.Open(postgres.Open(dsn))
	if err != nil {
		panic(err)
	}
	db.AutoMigrate(&category{})

	// 加载虚拟数据
	db.Create(&category{
		Code:             1,
		ParentCategoryId: nil,
	})
	db.Create(&category{
		Code:             2,
		ParentCategoryId: lo.ToPtr[uint](1),
	})
	db.Create(&category{
		Code:             3,
		ParentCategoryId: lo.ToPtr[uint](2),
	})
	db.Create(&category{
		Code:             4,
		ParentCategoryId: lo.ToPtr[uint](1),
	})

	// 读取逻辑
	var categories []category
	if err := db.Model(&category{}).Find(&categories).Error; err != nil {
		panic(err)
	}
	for _, v := range categories {
		if v.ParentCategoryId == nil {
			fmt.Printf("id: %v\tparentCategoryId: <nil>\n", v.Code)
			continue
		}
		fmt.Printf("id: %v\tparentCategoryId: %v\n", v.Code, *v.ParentCategoryId)
	}
}

如果我理解您的需求正确,您需要一个引用自身的表。这就是为什么我以这种方式定义了category结构体。每个类别都有自己的ParentCategoryId,除非该类别没有父类别。如果您尝试执行上述代码,您应该会得到类似以下的结果:

id: 1   parentCategoryId: <nil>
id: 2   parentCategoryId: 1
id: 3   parentCategoryId: 2
id: 4   parentCategoryId: 1

如果我对您的问题理解有误,请告诉我,我会更新我的回答,谢谢!

英文:

I should have managed your requirements with the following code:

package main

import (
	&quot;fmt&quot;

	&quot;github.com/samber/lo&quot;
	&quot;gorm.io/driver/postgres&quot;
	&quot;gorm.io/gorm&quot;
)

type category struct {
	Code             uint `gorm:&quot;unique;primaryKey;&quot;`
	ParentCategoryId *uint
	ParentCategory   *category `gorm:&quot;foreignKey:ParentCategoryId&quot;`
}

func main() {
	dsn := &quot;host=localhost port=54322 user=postgres password=postgres dbname=postgres sslmode=disable&quot;
	db, err := gorm.Open(postgres.Open(dsn))
	if err != nil {
		panic(err)
	}
	db.AutoMigrate(&amp;category{})

	// load dummy data
	db.Create(&amp;category{
		Code:             1,
		ParentCategoryId: nil,
	})
	db.Create(&amp;category{
		Code:             2,
		ParentCategoryId: lo.ToPtr[uint](1),
	})
	db.Create(&amp;category{
		Code:             3,
		ParentCategoryId: lo.ToPtr[uint](2),
	})
	db.Create(&amp;category{
		Code:             4,
		ParentCategoryId: lo.ToPtr[uint](1),
	})

	// reading logic
	var categories []category
	if err := db.Model(&amp;category{}).Find(&amp;categories).Error; err != nil {
		panic(err)
	}
	for _, v := range categories {
		if v.ParentCategoryId == nil {
			fmt.Printf(&quot;id: %v\tparentCategoryId: &lt;nil&gt;\n&quot;, v.Code)
			continue
		}
		fmt.Printf(&quot;id: %v\tparentCategoryId: %v\n&quot;, v.Code, *v.ParentCategoryId)
	}
}

If I got well your needs, you need to have a table that references itself. That's why I defined the category struct in this way. Each category has its own ParentCategoryId unless the category has no parent. If you try to execute the previous code, you should get something like:

id: 1   parentCategoryId: &lt;nil&gt;
id: 2   parentCategoryId: 1
id: 3   parentCategoryId: 2
id: 4   parentCategoryId: 1

Maybe I didn't get something from your question, if that's the case just let me know and I'll update my answer, thanks!

huangapple
  • 本文由 发表于 2023年6月20日 03:39:21
  • 转载请务必保留本文链接:https://go.coder-hub.com/76509628.html
匿名

发表评论

匿名网友

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

确定