在Go Gorm中添加具有多对多反向引用的记录

在Go Gorm中添加具有多对多反向引用的记录,go,go-gorm,Go,Go Gorm,Go Gorm中编写和更新返回引用多对多结构的记录的方法是什么 例如,我有一个具有自引用相关属性的联系人结构: type Contact struct { gorm.Model FirstName string `json:"first_name"` LastName string `json:"last_name"` MiddleName string `json:"midd

Go Gorm中编写和更新返回引用多对多结构的记录的方法是什么

例如,我有一个具有自引用相关属性的联系人结构:

type Contact struct {
    gorm.Model

    FirstName  string      `json:"first_name"`
    LastName   string      `json:"last_name"`
    MiddleName string      `json:"middle_name,omitempty"`
    Related    []Contact   `json:"related,omitempty" gorm:"many2many:related_contacts"`
}
填充两个相互引用的联系人

fred := model.Contact{
    FirstName:  "Fred",
    LastName:   "Jones",
    MiddleName: "B",
}

bill := model.Contact{
    FirstName:  "Bill",
    LastName:   "Brown",
    MiddleName: "R",
}

fred.Related = []model.Contact{bill}
bill.Related = []model.Contact{fred}
执行
db.Save(&fred)
将向数据库写入两条记录;一个用于bill,一个用于fred,然而,bill记录没有对fred的反向引用(因为它还没有被添加,并且没有ID)

如果我也执行
db.Save(&bill)
,我现在会得到4条记录,因为保存bill时不知道fred已经保存了

虽然我意识到我可以保存一个,然后找到第二个并更新它,但我想知道是否有更好的“Gorm方法”可以做到这一点,在添加记录时不必手动保持反向引用同步


此外,如果要删除fred,方法是什么?我需要手动处理相关的联系人表吗?

我认为您遇到的问题是,您在
bill.related
中的
fred
是一个副本,因此不会通过调用
db.Save(&fred)
更新其ID

调用
Save
gorm时,会检查任何模型的ID字段,以确定是否应创建或更新该模型

我想尝试的是:

fred:=model.Contact{
名字:“弗雷德”,
姓:“琼斯”,
中间名:“B”,
}
db.Save(&fred)
比尔:=型号。联系人{
名字:“比尔”,
姓:“布朗”,
中间名:“R”,
相关:[]型号。联系{fred},
}
db.Save(&bill)
//现在比尔和弗雷德都有身份证了
fred.Related=[]model.Contact{bill}
db.Save(&fred)
这里需要注意的一件事是,gorm是否试图保存
fred.Related[0]
,并进入无限循环。您可以通过以下方式进行管理。这意味着您将最后两行更改为:

fred.Related=[]模型。联系{bill}
db.Omit(“Related.*).Save(&fred)
//或者使用关联模式
db.模型(&fred).关联(“相关”).追加(&bill)

编辑:关于删除。不知道您正在使用哪个数据库,通常您必须自己管理相关的实体删除。如果您使用的数据库支持外键约束,则可以将联接表外键声明为删除级联上的
引用联系人(id)
。这意味着,如果您删除任何
联系人
,则联接表中包含相同ID的行也将自动删除。

我认为您遇到的问题是,您在
bill.Related
中的
fred
是一个副本,因此不会通过调用
db.Save(&fred)来更新其ID

调用
Save
gorm时,会检查任何模型的ID字段,以确定是否应创建或更新该模型

我想尝试的是:

fred:=model.Contact{
名字:“弗雷德”,
姓:“琼斯”,
中间名:“B”,
}
db.Save(&fred)
比尔:=型号。联系人{
名字:“比尔”,
姓:“布朗”,
中间名:“R”,
相关:[]型号。联系{fred},
}
db.Save(&bill)
//现在比尔和弗雷德都有身份证了
fred.Related=[]model.Contact{bill}
db.Save(&fred)
这里需要注意的一件事是,gorm是否试图保存
fred.Related[0]
,并进入无限循环。您可以通过以下方式进行管理。这意味着您将最后两行更改为:

fred.Related=[]模型。联系{bill}
db.Omit(“Related.*).Save(&fred)
//或者使用关联模式
db.模型(&fred).关联(“相关”).追加(&bill)

编辑:关于删除。不知道您正在使用哪个数据库,通常您必须自己管理相关的实体删除。如果您使用的数据库支持外键约束,则可以将联接表外键声明为删除级联上的
引用联系人(id)
。这意味着,如果删除任何
联系人
,则联接表中包含相同ID的行也将自动删除。

为模型中的每个结构进行保存的问题是来回发生的次数。我试着在顶级文档对象上保存一次,然后让Gorm来解决这个问题。通过广泛的测试,它似乎不够智能,无法理解结构之间的依赖关系。如果启用PRAGMA foreign_keys=on,您可以看到插入顺序不受外键关系的影响,这一点尤其明显。有趣的是,DELETE CASCADE上的
引用联系人(id)也因为同样的问题而不起作用。对于复杂的模型,Gorm无法识别删除顺序,并在删除子表之前尝试对父表发出删除,并且在删除模型的顶部元素时,约束失败。您是否尝试过使用指向模型的指针而不是值?如
相关[]*联系
。这可能会让您使用您首先提出的内容,但由于相关结构不是副本,而是相同的内存位,因此它们的ID将被填充,因此您应该在
联系人表中只保留两行,在联接表中保留两行,检查一下,问题不在于Gorm如何处理指针引用。它实际上是如何处理嵌套(级联)引用的。它看起来不够深,而且与物体交叉。它假定依赖关系始终是父子关系,而不是兄弟姐妹关系,也不是父子关系至少从我所能发现的情况来看,对模型中的每个结构进行保存的问题是来回发生的次数。我试着在顶级文档对象上保存一次,然后让Gorm来解决这个问题。通过广泛的测试,它似乎不是英特尔