关系数据库导致循环
Relational Database Resulting in Loop
我有以下层次结构,用户 -> 地图 -> 元素 -> Posts
一个用户可以有一堆地图,每个地图都会有一些元素,每个元素会有一些 posts.
类型用户结构{
UserID uint `gorm:"primarykey;autoIncrement;not_null"`
UserName string `json: user_name`
FirstName string `json: first_name`
LastName string `json: last_name`
Email string `json:email`
Password []byte `json:"-"`
Phone string `json:"phone"`
Maps []Map `gorm:"-"`
}
类型地图结构{
MapID uint `gorm:"primarykey;autoIncrement;not_null"`
UserID uint `json:userid`
User User `json:"user"; gorm:"foreignkey:UserID`
Title string `json:title`
Desc string `json: "desc"`
Elements []Element `gorm:"foreignKey:MapID"`
Date time.Time `json: date`
}
类型元素结构{
ElementID uint `gorm:"primarykey;autoIncrement;not_null"`
ElementName string `json: element_name`
Desc string `json: desc`
MapID uint `json:mapid`
Map Map `json:"map"; gorm:"foreignkey:MapID`
Posts []Post `gorm:"foreignKey:ElementID"`
Date time.Time `json: date`
UserID uint `json:userid`
User User `json:"user"; gorm:"foreignkey:UserID`
}
类型Post结构{
PostId uint `gorm:"primarykey;autoIncrement;not_null"`
Title string `json: p_title`
Subject string `json: subject`
Date time.Time `json: date`
Entry string `json: entry_text`
ElementID uint `json:elementid`
Element Element `json:"element"; gorm:"foreignkey:ElementID`
UserID uint `json:userid`
User User `json:"user"; gorm:"foreignkey:UserID`
}
这一切似乎工作正常,但现在当我从后端发送 JSON 响应时,似乎有可能出现无限循环。
当我检索用户的所有地图时,它会列出与创建地图的用户相关的用户对象,但地图随后还包含一个元素列表,在元素对象中它将列出它所属的地图,地图对象将再次列出它的所有元素。
那么我应该通过在一个方向上预加载层次结构来处理这个问题吗?
var getmaps[]models.Map
database.DB.Preload("User").Preload("Map").Preload("Elements").Offset(offset).Limit(limit).Find(&getmaps)
或者我应该修复 struct 和 gorm 设置以仅在一个方向上获得关系?因为 return 地图将 return 它的元素和每个元素将 return 它所属的地图循环回到它的元素等
这个循环也会发生在元素和 posts 中,其中一个元素将有许多 posts,那些 post 对象将显示它们的元素,而该元素对象将显示它的posts.
我确信有一个理想或最佳的方法来实现这个,所以很好奇人们会推荐什么。
使用以下预加载调用一张地图的示例
func DetailMap(c *fiber.Ctx) error {
id,_ := strconv.Atoi(c.Params("id"))
fmt.Println(id)
var smap models.Map
database.DB.Where("map_id=?", id).Preload("User").Preload("Map").Preload("Elements.Posts").First(&smap)
return c.JSON(fiber.Map{
"data":smap,
})
}
“数据”:{
"MapID": 1,
"UserID": 1,
"user": {
"UserID": 1,
"UserName": "Chris",
"FirstName": "Chris",
"LastName": "XxxXxxxx",
"Email": "xxxxx@gmail.com",
"phone": "123-456-6789",
"Maps": null
},
"Title": "My Map",
"Desc": "This is the subject",
"Elements": [
{
"ElementID": 1,
"ElementType": "BASE",
"ElementName": "Identity",
"BriefDesc": "This is the identity ",
"Desc": "In publishing and graphic design
"ParentId": "",
"NumElements": 0,
"NumEntries": 0,
"MapID": 1,
"map": {
"MapID": 0,
"UserID": 0,
"user": {
"UserID": 0,
"UserName": "",
"FirstName": "",
"LastName": "",
"Email": "",
"phone": "",
"Maps": null
},
"Title": "",
"Desc": "",
"Elements": null,
"Date": "0001-01-01T00:00:00Z"
},
"Notes": null,
"Questions": null,
"Posts": [
{
"PostId": 1,
"Title": "First Post",
"Subject": "This is the subject",
"Date": "2022-04-11T12:35:55.267-03:00",
"Entry": "This is the Entry",
"ElementID": 1,
"element": {
"ElementID": 0,
"ElementType": "",
"ElementName": "",
"BriefDesc": "",
"Desc": "",
"ParentId": "",
"NumElements": 0,
"NumEntries": 0,
"MapID": 0,
"map": {
"MapID": 0,
"UserID": 0,
"user": {
"UserID": 0,
"UserName": "",
"FirstName": "",
"LastName": "",
"Email": "",
"phone": "",
"Maps": null
},
"Title": "",
"Desc": "",
"Elements": null,
"Date": "0001-01-01T00:00:00Z"
},
"Notes": null,
"Questions": null,
"Posts": null,
"Date": "0001-01-01T00:00:00Z",
"UserID": 0,
"user": {
"UserID": 0,
"UserName": "",
"FirstName": "",
"LastName": "",
"Email": "",
"phone": "",
"Maps": null
}
},
"UserID": 1,
"user": {
"UserID": 0,
"UserName": "",
"FirstName": "",
"LastName": "",
"Email": "",
"phone": "",
"Maps": null
}
}
],
"Date": "2022-04-11T11:31:01.72-03:00",
"UserID": 1,
"user": {
"UserID": 0,
"UserName": "",
"FirstName": "",
"LastName": "",
"Email": "",
"phone": "",
"Maps": null
}
},`
在您的 Post
、Map
和 Element
结构中,您具有以下字段:
UserID uint `json:userid`
User User `json:"user"; gorm:"foreignkey:UserID`
您应该从您的内容结构中删除 User
字段,因为您已经有一个 UserID
。在这种情况下,“引用”(ID) 比包括整个用户对象更明智。如果需要,客户端可以调用 /users/{id}
端点并查找更多信息。
还通过删除 Maps []Map
来限制 User
结构的内容(负责您提到的循环)。然后,您需要设置 /user/{id}/maps
等端点,以便客户端可以获取用户的内容。
Post
和Element
也是如此。您可以选择 all-out 并仅存储 ID,或者您可以存储仅包含“子”模型的数组。 (地图嵌入元素,元素不嵌入地图)。因此,要查找元素的关联映射,您可以调用端点 /maps/{your element's map ID}
。元素相同 > Post
type Map struct {
gorm.Model // this takes care of the ID field
UserID uint `json:userid`
Title string `json:title`
Desc string `json: "desc"`
Elements []Element // gorm will handle the relationship automatically
Date time.Time `json: date`
}
type Element struct {
gorm.Model // includes ID
ElementName string `json: element_name`
Desc string `json: desc`
MapID uint `json:mapid`
// Map Map ... This relationship is described by another endpoint - /elements/{elementId}/map to get the related map
Posts []Post // gorm handles this
Date time.Time `json: date`
UserID uint `json:userid`
}
type Post struct {
gorm.Model
Title string `json: p_title`
Subject string `json: subject`
Date time.Time `json: date`
Entry string `json: entry_text`
ElementID uint `json:elementid` // gorm will use this as fk
UserID uint `json:userid`
}
为避免循环,您需要在结构级别建立关系 one-directional,并设置更多的 http 路由以朝另一个方向发展(参见注释代码)。
我描述的是一个简单的 REST api。 Microsoft 有一个很好的概述:https://docs.microsoft.com/en-us/azure/architecture/best-practices/api-design#organize-the-api-design-around-resources - 特别是 customer/order 关系会让您感兴趣。
在 gorm 方面,您将使用 one-to-many 关联:https://gorm.io/docs/has_many.html
我有以下层次结构,用户 -> 地图 -> 元素 -> Posts 一个用户可以有一堆地图,每个地图都会有一些元素,每个元素会有一些 posts.
类型用户结构{
UserID uint `gorm:"primarykey;autoIncrement;not_null"`
UserName string `json: user_name`
FirstName string `json: first_name`
LastName string `json: last_name`
Email string `json:email`
Password []byte `json:"-"`
Phone string `json:"phone"`
Maps []Map `gorm:"-"`
}
类型地图结构{
MapID uint `gorm:"primarykey;autoIncrement;not_null"`
UserID uint `json:userid`
User User `json:"user"; gorm:"foreignkey:UserID`
Title string `json:title`
Desc string `json: "desc"`
Elements []Element `gorm:"foreignKey:MapID"`
Date time.Time `json: date`
}
类型元素结构{
ElementID uint `gorm:"primarykey;autoIncrement;not_null"`
ElementName string `json: element_name`
Desc string `json: desc`
MapID uint `json:mapid`
Map Map `json:"map"; gorm:"foreignkey:MapID`
Posts []Post `gorm:"foreignKey:ElementID"`
Date time.Time `json: date`
UserID uint `json:userid`
User User `json:"user"; gorm:"foreignkey:UserID`
}
类型Post结构{
PostId uint `gorm:"primarykey;autoIncrement;not_null"`
Title string `json: p_title`
Subject string `json: subject`
Date time.Time `json: date`
Entry string `json: entry_text`
ElementID uint `json:elementid`
Element Element `json:"element"; gorm:"foreignkey:ElementID`
UserID uint `json:userid`
User User `json:"user"; gorm:"foreignkey:UserID`
}
这一切似乎工作正常,但现在当我从后端发送 JSON 响应时,似乎有可能出现无限循环。
当我检索用户的所有地图时,它会列出与创建地图的用户相关的用户对象,但地图随后还包含一个元素列表,在元素对象中它将列出它所属的地图,地图对象将再次列出它的所有元素。
那么我应该通过在一个方向上预加载层次结构来处理这个问题吗?
var getmaps[]models.Map database.DB.Preload("User").Preload("Map").Preload("Elements").Offset(offset).Limit(limit).Find(&getmaps)
或者我应该修复 struct 和 gorm 设置以仅在一个方向上获得关系?因为 return 地图将 return 它的元素和每个元素将 return 它所属的地图循环回到它的元素等
这个循环也会发生在元素和 posts 中,其中一个元素将有许多 posts,那些 post 对象将显示它们的元素,而该元素对象将显示它的posts.
我确信有一个理想或最佳的方法来实现这个,所以很好奇人们会推荐什么。
使用以下预加载调用一张地图的示例
func DetailMap(c *fiber.Ctx) error {
id,_ := strconv.Atoi(c.Params("id"))
fmt.Println(id)
var smap models.Map
database.DB.Where("map_id=?", id).Preload("User").Preload("Map").Preload("Elements.Posts").First(&smap)
return c.JSON(fiber.Map{
"data":smap,
})
}
“数据”:{
"MapID": 1,
"UserID": 1,
"user": {
"UserID": 1,
"UserName": "Chris",
"FirstName": "Chris",
"LastName": "XxxXxxxx",
"Email": "xxxxx@gmail.com",
"phone": "123-456-6789",
"Maps": null
},
"Title": "My Map",
"Desc": "This is the subject",
"Elements": [
{
"ElementID": 1,
"ElementType": "BASE",
"ElementName": "Identity",
"BriefDesc": "This is the identity ",
"Desc": "In publishing and graphic design
"ParentId": "",
"NumElements": 0,
"NumEntries": 0,
"MapID": 1,
"map": {
"MapID": 0,
"UserID": 0,
"user": {
"UserID": 0,
"UserName": "",
"FirstName": "",
"LastName": "",
"Email": "",
"phone": "",
"Maps": null
},
"Title": "",
"Desc": "",
"Elements": null,
"Date": "0001-01-01T00:00:00Z"
},
"Notes": null,
"Questions": null,
"Posts": [
{
"PostId": 1,
"Title": "First Post",
"Subject": "This is the subject",
"Date": "2022-04-11T12:35:55.267-03:00",
"Entry": "This is the Entry",
"ElementID": 1,
"element": {
"ElementID": 0,
"ElementType": "",
"ElementName": "",
"BriefDesc": "",
"Desc": "",
"ParentId": "",
"NumElements": 0,
"NumEntries": 0,
"MapID": 0,
"map": {
"MapID": 0,
"UserID": 0,
"user": {
"UserID": 0,
"UserName": "",
"FirstName": "",
"LastName": "",
"Email": "",
"phone": "",
"Maps": null
},
"Title": "",
"Desc": "",
"Elements": null,
"Date": "0001-01-01T00:00:00Z"
},
"Notes": null,
"Questions": null,
"Posts": null,
"Date": "0001-01-01T00:00:00Z",
"UserID": 0,
"user": {
"UserID": 0,
"UserName": "",
"FirstName": "",
"LastName": "",
"Email": "",
"phone": "",
"Maps": null
}
},
"UserID": 1,
"user": {
"UserID": 0,
"UserName": "",
"FirstName": "",
"LastName": "",
"Email": "",
"phone": "",
"Maps": null
}
}
],
"Date": "2022-04-11T11:31:01.72-03:00",
"UserID": 1,
"user": {
"UserID": 0,
"UserName": "",
"FirstName": "",
"LastName": "",
"Email": "",
"phone": "",
"Maps": null
}
},`
在您的 Post
、Map
和 Element
结构中,您具有以下字段:
UserID uint `json:userid`
User User `json:"user"; gorm:"foreignkey:UserID`
您应该从您的内容结构中删除 User
字段,因为您已经有一个 UserID
。在这种情况下,“引用”(ID) 比包括整个用户对象更明智。如果需要,客户端可以调用 /users/{id}
端点并查找更多信息。
还通过删除 Maps []Map
来限制 User
结构的内容(负责您提到的循环)。然后,您需要设置 /user/{id}/maps
等端点,以便客户端可以获取用户的内容。
Post
和Element
也是如此。您可以选择 all-out 并仅存储 ID,或者您可以存储仅包含“子”模型的数组。 (地图嵌入元素,元素不嵌入地图)。因此,要查找元素的关联映射,您可以调用端点 /maps/{your element's map ID}
。元素相同 > Post
type Map struct {
gorm.Model // this takes care of the ID field
UserID uint `json:userid`
Title string `json:title`
Desc string `json: "desc"`
Elements []Element // gorm will handle the relationship automatically
Date time.Time `json: date`
}
type Element struct {
gorm.Model // includes ID
ElementName string `json: element_name`
Desc string `json: desc`
MapID uint `json:mapid`
// Map Map ... This relationship is described by another endpoint - /elements/{elementId}/map to get the related map
Posts []Post // gorm handles this
Date time.Time `json: date`
UserID uint `json:userid`
}
type Post struct {
gorm.Model
Title string `json: p_title`
Subject string `json: subject`
Date time.Time `json: date`
Entry string `json: entry_text`
ElementID uint `json:elementid` // gorm will use this as fk
UserID uint `json:userid`
}
为避免循环,您需要在结构级别建立关系 one-directional,并设置更多的 http 路由以朝另一个方向发展(参见注释代码)。
我描述的是一个简单的 REST api。 Microsoft 有一个很好的概述:https://docs.microsoft.com/en-us/azure/architecture/best-practices/api-design#organize-the-api-design-around-resources - 特别是 customer/order 关系会让您感兴趣。
在 gorm 方面,您将使用 one-to-many 关联:https://gorm.io/docs/has_many.html