Go语言 如何配置我的数据库关系以便我可以插入我的实体?

0yg35tkg  于 2023-09-28  发布在  Go
关注(0)|答案(1)|浏览(99)

我有一叠

type Stack struct {
    Name             string           `json:"name" gorm:"primaryKey"`
    Parameters       []StackParameter `json:"parameters" gorm:"foreignKey:StackName; references: Name; constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
    ...
}

Stack有一些参数。多个堆栈可以具有相同的参数,因此我使用参数NameStackName作为主复合键

type StackParameter struct {
    Name         string  `json:"name" gorm:"primaryKey"`
    StackName    string  `json:"-" gorm:"primaryKey"`
    DefaultValue *string `json:"defaultValue"`
    ...
}

我希望能够部署堆栈链。所以我有一条链子

type Chain struct {
    ID          uint      `json:"id" gorm:"primaryKey"`
    Name        string `json:"name" gorm:"index:idx_name_and_group,unique"`
    Description string `json:"description"`
    GroupName   string `json:"groupName" gorm:"index:idx_name_and_group,unique; references:Name"`
    Group       *Group `json:"group,omitempty"`
    Links       []*Link `json:"links"`
}

Chain有一些链接

type Link struct {
    ID        uint      `json:"id" gorm:"primaryKey"`
    ChainID uint  `json:"chainId"`
    Chain   Chain `json:"chain"`

    StackName string `json:"stackName" gorm:"references:Name"`
    Stack     Stack  `json:"stack"`
    Parameters []*LinkParameter `json:"parameters" gorm:"foreignKey:LinkID"`
}

LinkStack的一个示例,把它看作类/对象,所以它的参数由Stack的参数定义。

type LinkParameter struct {
    LinkID         uint           `json:"linkId" gorm:"primaryKey"`
    Name           string         `json:"name" gorm:"primaryKey"`
    StackParameter StackParameter `json:"-" gorm:"foreignKey:Name,StackName; references:Name,StackName; constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
    StackName      string         `json:"-"`
    Value          string         `json:"value"`
}

因此,LinkParameter属于Link,并具有由StackParameter定义的唯一名称,并为这两个定义了Value
为了简洁起见,我将省略处理程序、服务和存储库代码,但主要目标是用LinkParameter保存Link,我尝试使用

err := r.db.Session(&gorm.Session{FullSaveAssociations: true}).Save(link).Error

但我得到了以下错误

[im-manager] 2023/08/13 09:29:21 /src/pkg/instance/repository.go:50 ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification (SQLSTATE 42P10)
[im-manager] [0.291ms] [rows:0] INSERT INTO "link_parameters" ("link_id","stack_parameter_name","stack_name","value") VALUES (5,'STARTUP_PROBE_FAILURE_THRESHOLD','whoami-go','STARTUP_PROBE_FAILURE_THRESHOLD'),(5,'STARTUP_PROBE_PERIOD_SECONDS','whoami-go','STARTUP_PROBE_PERIOD_SECONDS') ON CONFLICT ("link_id","stack_parameter_name") DO UPDATE SET "stack_name"="excluded"."stack_name","value"="excluded"."value"
[im-manager] 
[im-manager] 2023/08/13 09:29:21 /src/pkg/instance/repository.go:50 ERROR: there is no unique or exclusion constraint matching the ON CONFLICT specification (SQLSTATE 42P10)
[im-manager] [1.279ms] [rows:1] INSERT INTO "links" ("created_at","updated_at","chain_id","stack_name","preset","preset_id","public","deploy_log") VALUES ('2023-08-13 09:29:21.319','2023-08-13 09:29:21.319',1,'whoami-go',false,0,false,'') RETURNING "id"

背景更新:
我实际上要做的是从部署一个Instance到部署一个Chain示例,我现在称之为Link。这已经工作了很长时间了。所以我基本上只是试图将Instance结构体拆分为一个包含LinkChain结构体。
根据@TiGo的建议,我现在得到了

[im-manager] 2023/08/14 03:27:24 /src/pkg/instance/repository.go:54 ERROR: ON CONFLICT DO UPDATE requires inference specification or constraint name (SQLSTATE 42601)
[im-manager] [0.237ms] [rows:0] INSERT INTO "link_parameters" ("link_id","stack_parameter_name","stack_name","value") VALUES (18,'REPLICA_COUNT','whoami-go','1'),(18,'IMAGE_PULL_POLICY','whoami-go','Always') ON CONFLICT DO UPDATE SET "link_id"="excluded"."link_id","stack_parameter_name"="excluded"."stack_parameter_name","stack_name"="excluded"."stack_name","value"="excluded"."value"
[im-manager] 
[im-manager] 2023/08/14 03:27:24 /src/pkg/instance/repository.go:54 ERROR: ON CONFLICT DO UPDATE requires inference specification or constraint name (SQLSTATE 42601)
[im-manager] [2.106ms] [rows:1] INSERT INTO "links" ("created_at","updated_at","chain_id","stack_name","preset","preset_id","public","deploy_log") VALUES ('2023-08-14 03:27:24.802','2023-08-14 03:27:24.802',1,'whoami-go',false,0,false,'') RETURNING "id"

另一个更新:
如果我将LinkParameter结构体的Name属性更改为ParameterName,这似乎可以工作,因此它看起来如下所示

type LinkParameter struct {
    LinkID         uint           `json:"-" gorm:"primaryKey"`
    ParameterName  string         `json:"name" gorm:"primaryKey"`
    StackParameter StackParameter `json:"-" gorm:"foreignKey:ParameterName,StackName; references:Name,StackName; constraint:OnUpdate:CASCADE,OnDelete:CASCADE"`
    StackName      string         `json:"-"`
    Value          string         `json:"value"`
}

有谁能告诉我为什么要这样做吗?

yyyllmsg

yyyllmsg1#

发生错误的原因是LinkParameter表在(link_id, stack_parameter_name)上没有与ON CONFLICT子句匹配的唯一约束。
当使用ON CONFLICT执行INSERT时,PostgreSQL需要在ON CONFLICT中指定的列上存在唯一的索引/约束。这允许它正确地检测冲突。
要修复它,需要在LinkParameter表中的(link_id, stack_parameter_name)上添加一个唯一约束:

type LinkParameter struct {
  //...

  LinkID string `gorm:"uniqueIndex:link_param_idx"` 
  Name string `gorm:"uniqueIndex:link_param_idx"`

  // ...
}

这将在(link_id,name)上创建唯一约束“link_param_idx”。
然后你的冲突将按预期工作。所以总结一下:

  • 在ON CONFLICT中指定的列上添加唯一索引
  • 这允许PostgreSQL检测插入时的冲突
  • 然后将正确触发ON CONFLICT DO UPDATE子句

相关问题