站长网站,metasploit wordpress,网页推广怎么做,网站全能空间gorm day8
gorm Has Many关系gorm Many To Many关系 gorm Has Many关系
Has Many
在GORM#xff08;Go的一个对象关系映射库#xff09;中#xff0c;“Has Many” 关系表示一个实体与另一个实体之间的一对多关系。这意味着一个实体#xff08;我们称之为父…gorm day8
gorm Has Many关系gorm Many To Many关系 gorm Has Many关系
Has Many
在GORMGo的一个对象关系映射库中“Has Many” 关系表示一个实体与另一个实体之间的一对多关系。这意味着一个实体我们称之为父实体可以拥有指向多个其他实体子实体的引用。这种关系在数据库中通常通过使用外键在子实体上来实现。
举个例子来说明GORM中定义和使用的Has Many关系 示例用户和订单 假设我们有两个模型User 和 Order。一个用户可以拥有多个订单但每个订单只能属于一个用户。这是一个典型的Has Many关系。
package mainimport (gorm.io/driver/sqlitegorm.io/gorm
)type User struct {gorm.ModelName stringOrders []Order // Has Many 关系
}type Order struct {gorm.ModelProductName stringUserID uint // 外键
}func main() {db, err : gorm.Open(sqlite.Open(test.db), gorm.Config{})if err ! nil {panic(failed to connect database)}// 自动迁移模式db.AutoMigrate(User{}, Order{})// 创建用户和订单user : User{Name: John Doe, Orders: []Order{{ProductName: Book},{ProductName: Pen},}}db.Create(user) // GORM 会自动处理外键关系
}
定义模型我们定义了两个结构体 User 和 Order 来作为我们的模型。User 结构体中包含一个 Orders 字段它是一个 Order 结构体切片表示一个用户可以有多个订单。 外键在 Order 结构体中UserID 字段作为外键用来存储创建该订单的用户的ID。这个字段告诉GORM这两个模型之间的关联方式。 自动迁移db.AutoMigrate(User{}, Order{}) 告诉GORM自动创建或修改数据库表以匹配模型的结构。这包括设置正确的外键关系。 创建记录当我们创建一个 User 实例并设置其 Orders 字段时GORM知道如何将订单记录插入 orders 表并设置每个订单的 UserID 字段以反映它们属于该用户。
文档例子 has many与另一个模型建立了一对多的连接。不同于has one拥有者可以有零或多个关联模型。 例如您的应用包含user和credit card模型且每个user可以有多张credit card。
// User 有多张 CreditCardUserID 是外键
type User struct {gorm.ModelCreditCards []CreditCard
}type CreditCard struct {gorm.ModelNumber stringUserID uint
}
这个看起来就还是很直观的。之间的关系还是很清楚的。 User结构体代表应用中的用户。它继承了gorm.Model这是GORM提供的基础模型包含了一些常用字段如ID, CreatedAt, UpdatedAt, DeletedAt。User结构体中包含一个CreditCards字段这是一个CreditCard结构体的切片。这表明一个用户可以关联多张信用卡。GORM通过这个字段理解到User和CreditCard之间存在一对多关系。
CreditCard结构体代表信用卡。同样继承了gorm.Model并且有一个Number字段存储信用卡号以及一个UserID字段。UserID是一个无符号整型用于存储这张信用卡所属用户的ID。这个字段是实现一对多关系的外键它指向User表的主键ID。
关系和外键 在这个关系中UserID字段在CreditCard结构体内充当外键指向User表的ID字段。这表示每张CreditCard都属于一个特定的User。
当使用GORM进行数据库操作如创建、查询时GORM会自动处理这些关联关系。例如当你为一个User添加多张CreditCard并保存到数据库时GORM会自动填充每张CreditCard的UserID字段确保关系的正确性。
重写外键
要定义has many关系通用必须存在外键。默认的外键名是拥有者的类型名加上其主键字段名。 例如要定义一个属于User的模型则其外键应该是UserID。 此外想要使用另一个字段作为外键你可以使用foreignKey标签自定义它
type User struct {gorm.ModelCreditCards []CreditCard gorm:foreignKey:UserRefer
}type CreditCard struct {gorm.ModelNumber stringUserRefer uint
}
解读 在GORM中定义Has Many关系时确实需要有一个外键存在于子模型中用以指向父模型的主键从而表明两者之间的关联。这段内容详细解释了如何在GORM中设置和自定义这种一对多“Has Many”关系以及如何指定外键。
默认外键命名规则 GORM的默认行为是根据父模型的类型名和其主键字段名来自动生成外键名。例如如果有一个模型叫User父模型其主键字段名默认是ID因为gorm.Model包含一个名为ID的字段作为主键那么属于User的任何模型子模型的默认外键名将会是UserID。
自定义外键 管GORM提供了一个默认的外键命名规则但在某些情况下默认规则可能不适合你的数据库设计。可能你想要的外键名与默认提供的不同或者你的数据库已经有了既定的外键命名规范。为了满足这种需求GORM允许通过foreignKey标签来自定义外键字段。
示例解读 在给定的示例中User模型和CreditCard模型之间存在一个Has Many关系即一个用户可以拥有多张信用卡。示例通过在User结构体中的CreditCards字段旁使用gorm:foreignKey:UserRefer标签明确指定了CreditCard模型使用UserRefer字段作为外键而不是默认的UserID。
这意味着 User模型通过CreditCards字段关联多张CreditCard。 在CreditCard模型中UserRefer字段被用作外键指向User模型的主键ID字段。这个指向的意思是子表中的外键字段的值对应于父表中某条记录的主键值。 这种关系允许GORM在操作数据库时自动处理这些关联比如在查询用户时同时获取其所有信用卡信息。
重写引用
GORM 通常使用使用者的主键作为外键的值。对于上面的例子它是User的ID字段。 为user添加credit card时GORM会将user的ID字段保存到credit card的UserID字段。 同样的您也可以使用标签references来更改它例如
type User struct {gorm.ModelMemberNumber stringCreditCards []CreditCard gorm:foreignKey:UserNumber;references:MemberNumber
}type CreditCard struct {gorm.ModelNumber stringUserNumber string
}
这里我主要说说references references:MemberNumber是GORM中用于自定义外键关联的一个标签它指定了在建立模型间关系时应该引用的字段。 当你在GORM中定义模型关系时foreignKey和references标签通常一起使用来指明这种自定义关系。 让我来具体解释一下references:MemberNumber的作用和意义。
默认外键引用 在没有明确指定references标签的情况下GORM默认使用父模型的主键字段通常是ID字段作为外键关联的引用。这意味着在一对多Has Many或一对一Has One关系中子模型中的外键字段将会存储与父模型的ID字段相对应的值。
自定义外键引用 使用references标签你可以指定一个不同于父模型的ID字段的其他字段作为外键引用。这在你想要建立模型间关系但又不想使用默认的ID字段作为关联依据时非常有用。
例子解读 references:MemberNumber告诉GORM当建立User和CreditCard之间的关系时不是使用User模型的ID字段而是使用User模型中的MemberNumber字段作为引用。这意味着 CreditCard模型中的UserNumber字段将会存储对应User模型中MemberNumber字段的值。 这样的设计使得CreditCard与User之间的关联不再依赖于用户的ID而是依赖于用户的MemberNumber这可能是一个业务逻辑上的需求例如当MemberNumber是用户在系统中的一个业务标识符时。
作用和好处 这种自定义关系的好处是提供了更大的灵活性允许开发者根据实际的业务需求和数据模型设计来建立模型间的关系。它特别有用于那些需要根据非主键字段建立关系的场景从而可以更准确地反映实际的业务逻辑和数据关系。
多态关联
GORM为has one和has many提供了多态关联支持他会将拥有者实体的表名、主键都保存到多态类型的字段中。
type Dog struct {ID intName stringToys []Toy gorm:polymorphic:Owner;
}type Toy struct {ID intName stringOwnerID intOwnerType string
}db.Create(Dog{Name: dog1, Toys: []Toy{{Name: toy1}, {Name: toy2}}})
// INSERT INTO dogs (name) VALUES (dog1)
// INSERT INTO toys (name,owner_id,owner_type) VALUES (toy1,1,dogs), (toy2,1,dogs)
解读 这段内容介绍了GORM如何实现和支持多态关联Polymorphic Associations对于Has One和Has Many关系。多态关联是一种数据库设计模式允许一个模型在这个例子中是Toy关联到多个模型如Dog、Cat等而不是只能关联到一个固定的模型。这种设计增加了数据库模型的灵活性和复用性。
示例解析 在给定的例子中Dog和Toy模型通过多态关系进行关联。这种关系允许Toy不仅仅属于Dog也可以属于其他类型的实体如Cat等只要它们采用相同的多态设计模式。
Dog模型 Dog模型简单明了包含ID和Name字段。此外它包含一个Toys字段这是一个Toy切片表示每只狗可以拥有多个玩具。通过gorm:polymorphic:Owner;标签GORM知道这是一个多态关联。
Toy模型 Toy模型包含ID、Name、OwnerID和OwnerType字段。OwnerID和OwnerType是实现多态关联的关键 OwnerID存储拥有者的主键值。 OwnerType存储拥有者的类型通常是拥有者实体的表名。
数据库操作示例 当创建一个Dog实例并为其分配玩具时如db.Create(Dog{Name: “dog1”, Toys: []Toy{{Name: “toy1”}, {Name: “toy2”}}})GORM会先在dogs表中插入一条记录然后在toys表中插入两条记录。 在toys表中每个玩具的owner_id会被设置为对应Dog实例的ID而owner_type会被设置为dogs。这样就实现了多态关联Toy知道它属于哪个表的哪条记录。
作用和好处 多态关联的主要好处是提供了极高的灵活性。 在没有多态关联的情况下如果你想让Toy既可以属于Dog也可以属于Cat你可能需要为每种关系创建不同的字段比如dog_id和cat_id或者创建不同的关联表。多态关联避免了这种冗余允许Toy通过OwnerID和OwnerType字段灵活地关联到任意类型的实体。
总结 这种设计模式在实际应用中非常有用尤其是在存在多种类型的实体并且这些实体都可能与某个资源有关联时。通过多态关联可以简化模型设计减少数据库复杂性同时保持了数据结构的灵活性和扩展性。
你可以使用标签polymorphicValue来更改多态类型的值例如
type Dog struct {ID intName stringToys []Toy gorm:polymorphic:Owner;polymorphicValue:master
}type Toy struct {ID intName stringOwnerID intOwnerType string
}db.Create(Dog{Name: dog1, Toys: []Toy{{Name: toy1}, {Name: toy2}}})
// INSERT INTO dogs (name) VALUES (dog1)
// INSERT INTO toys (name,owner_id,owner_type) VALUES (toy1,1,master), (toy2,1,master)
解读 这段内容介绍了如何在使用GORM进行多态关联时通过polymorphicValue标签自定义多态类型的值。在多态关联中通常需要两个字段来确定关联的目标一个是指向目标实体主键的外键如OwnerID另一个是表示目标实体类型的字段如OwnerType。通过polymorphicValue标签我们可以明确指定在创建关联时OwnerType字段应该保存的具体值而不是使用默认的表名。
总结使用polymorphicValue标签允许开发者在设计数据库模型时拥有更高的灵活性和控制权。它使得开发者可以根据业务逻辑需要自定义多态关联中OwnerType字段的值而不是简单地使用表名。
预加载
GORM 可以通过Preload预加载has many关联的记录。
自引用Has Many
type User struct {gorm.ModelName stringManagerID *uintTeam []User gorm:foreignkey:ManagerID
}
解读
这段内容展示了如何在使用GORM一个Go语言的ORM库定义自引用的Has Many关系。在这个例子中User模型通过自引用来表示一个组织结构其中一个用户可以是另一个用户的经理或上级并且一个经理可以管理多个下属。这种关系在数据库中通常用于表示层级或树状结构如员工和他们的管理者。
结构体定义 ManagerID: 指向另一个User实例的指针代表这个用户的经理。这是一个可空字段因为它是一个指针允许某些用户没有经理例如最高级别的经理。 Team: 一个User切片通过gorm:foreignkey:ManagerID标签指明这个切片表示所有将当前用户实例作为经理的用户集合。这里使用的foreignkey:ManagerID标签告诉GORMTeam字段中的用户是通过ManagerID字段与当前用户关联的。
自引用的Has Many关系 在这个模型中ManagerID字段用于标识每个用户的直接上级经理而Team字段则用于收集所有直接下属。通过这种方式你可以构建一个组织中所有员工的层级关系。例如如果一个用户A的ManagerID指向另一个用户B那么用户B的Team切片将包含用户A表示用户A是用户B的下属。
实现细节 自引用这个模型利用了自引用即User结构体中包含了指向相同类型User的字段。这在Go中是允许的并且在ORM中用于表示复杂的关系如树形结构或图结构。
外键关联通过gorm:foreignkey:ManagerID标签GORM知道如何将User表中的记录通过ManagerID连接起来建立一种层级关系。这允许GORM在执行查询时能够自动解析这些关系例如在查询一个用户时同时获取他的直接下属列表。
外键约束
你可以通过constraintOnUpdate、OnDelete实现外键约束在使用GORM进行迁移时它会被字段创建。例如
type User struct {gorm.ModelCreditCards []CreditCard gorm:constraint:OnUpdate:CASCADE,OnDelete:SET NULL;
}type CreditCard struct {gorm.ModelNumber stringUserID uint
}
你也可以在删除记录时通过Select来删除has many关联的记录。 gorm Many To Many关系
Many To Many
在GORM中Many To Many关系是指两个模型之间存在的关联其中一个实例可以关联到多个实例反之亦然。这种关系通常通过一个关联表或称为连接表来实现该表存储两个模型之间关联的外键。
示例用户和角色 假设我们有两个模型User和Role。一个用户可以有多个角色同时一个角色也可以被多个用户共享。这是一个典型的Many To Many关系。
定义模型 首先我们定义User和Role模型并使用GORM的标签来描述它们之间的Many To Many关系。
package mainimport (gorm.io/driver/sqlitegorm.io/gorm
)type User struct {gorm.ModelName stringRoles []Role gorm:many2many:user_roles;
}type Role struct {gorm.ModelName stringUsers []User gorm:many2many:user_roles;
}
在这个例子中User和Role模型通过Roles和Users字段相互关联而gorm:many2many:user_roles;标签指定了用于存储这种多对多关系的关联表名称为user_roles。
自动迁移 GORM提供自动迁移功能可以根据模型定义自动创建或更新数据库表结构。
func main() {db, err : gorm.Open(sqlite.Open(test.db), gorm.Config{})if err ! nil {panic(failed to connect database)}// 自动迁移db.AutoMigrate(User{}, Role{})
}
创建关联 接下来我们可以创建一些User和Role实例并设置它们之间的关联。
func main() {// ...数据库连接和自动迁移代码// 创建角色adminRole : Role{Name: Admin}userRole : Role{Name: User}db.Create(adminRole)db.Create(userRole)// 创建用户并分配角色user : User{Name: John, Roles: []Role{adminRole, userRole}}db.Create(user)
}
在上面的代码中我们首先创建了两个Role实例Admin和User。然后我们创建了一个User实例John并通过Roles字段将John与这两个角色关联起来。当我们执行db.Create(user)时GORM会自动处理这些关联不仅在users和roles表中插入相应的记录还会在user_roles关联表中插入表示这些关联的记录。
小结 通过GORM我们可以相对简单地实现和管理Many To Many关系。GORM自动处理关联表的创建和更新开发者只需专注于模型的定义和业务逻辑。这种抽象使得处理复杂的数据库关联变得更加直观和高效。
gorm文档解读
Many to Many会在两个model中添加一张连接表 例如你的英语包含了user和language且一个user可以说多种language多个user也可以说一种language。
// User 拥有并属于多种 languageuser_languages 是连接表
type User struct {gorm.ModelLanguages []Language gorm:many2many:user_languages;
}type Language struct {gorm.ModelName string
}
当使用GORM的AutoMigrate为User创建表时GORM会自动创建连接表。
反向引用
// User 拥有并属于多种 languageuser_languages 是连接表
type User struct {gorm.ModelLanguages []*Language gorm:many2many:user_languages;
}type Language struct {gorm.ModelName stringUsers []*User gorm:many2many:user_languages;
}
解读 这段内容展示了如何在GORM中实现和使用**Many To Many关系的反向引用。**在这个示例中有两个模型User和Language。一个用户可以会说多种语言同时一种语言也可以被多个用户所会说。这种关系通过一个名为user_languages的连接表来表示和存储。连接表是在数据库中用来存储两个表之间多对多关系的第三个表它通常包含指向两个表主键的外键。
User模型 User模型包含一个Languages字段这是一个指向Language结构的指针切片。这表明一个User可以关联多个Language。 gorm:many2many:user_languages;标签指定了用来存储User和Language之间关系的连接表名称为user_languages。这个标签告诉GORM如何管理这两个模型之间的多对多关系。
Language模型 Language模型类似地定义了一个Users字段这是一个指向User结构的指针切片。这表示一个Language可以被多个User所使用。 它同样使用了gorm:many2many:user_languages;标签来指定连接表。这样GORM就知道如何通过user_languages表反向管理Language到User的多对多关系。
连接表user_languages 连接表user_languages在数据库中通常会有两个主要的列一个是user_id列用来存储User表中某个用户的ID另一个是language_id列用来存储Language表中某种语言的ID。每一行代表一个用户与一种语言之间的关系。
反向引用的作用 双向查询这种反向引用的设置允许你从两个方向查询关系。即你可以轻松地找到一个用户会说的所有语言也可以找到说某种语言的所有用户。 数据完整性通过管理user_languages连接表GORM能够确保在添加、更新或删除用户和语言时保持数据的一致性和完整性。 灵活性这种模型设计提供了很高的灵活性适用于需要双向多对多关系的场景比如用户和群组、商品和分类等。
总结通过使用GORM的many2many标签和指定连接表你可以方便地在两个模型之间建立和管理复杂的多对多关系同时保持代码的清晰和数据库的整洁。
重写外键
对于many2many关系连接表会同时拥有两个模型的外键例如
type User struct {gorm.ModelLanguages []Language gorm:many2many:user_languages;
}type Language struct {gorm.ModelName string
}// 连接表user_languages
// foreign key: user_id, reference: users.id
// foreign key: language_id, reference: languages.id
若要重写它们可以使用标签foreignKeyreferences、joinforeignKey、joinReferences。当然您不需要使用全部的标签你可以仅使用其中的一个重写部分的外键、引用。
type User struct {gorm.ModelProfiles []Profile gorm:many2many:user_profiles;foreignKey:Refer;joinForeignKey:UserReferID;References:UserRefer;joinReferences:ProfileReferRefer uint gorm:index:,unique
}type Profile struct {gorm.ModelName stringUserRefer uint gorm:index:,unique
}// 会创建连接表user_profiles
// foreign key: user_refer_id, reference: users.refer
// foreign key: profile_refer, reference: profiles.user_refer
注意某些数据库只允许在唯一索引字段上创建外键如果你在迁移时会创建外键则需要指定unique index标签
解读 在GORM中通过使用many2many标签你可以定义两个模型之间的多对多关系并且默认情况下GORM会自动创建一个连接表来管理这种关系。连接表包含两个外键分别指向参与关系的两个模型的主键。然而有时候默认的外键和引用规则可能不符合你的数据库设计需求这时候你可以使用foreignKey、references、joinForeignKey、和joinReferences标签来重写这些规则。
标签解释 foreignKey: 指定本模型在连接表中使用的外键字段。 references: 指定foreignKey指向本模型中的哪个字段。 joinForeignKey: 指定另一模型在连接表中使用的外键字段。 joinReferences: 指定joinForeignKey指向另一模型中的哪个字段。
示例解读 在提供的示例中User和Profile模型通过一个名为user_profiles的连接表建立多对多关系。与前面的User和Language模型的默认外键规则不同这里通过标签明确指定了连接表中使用的外键名称和它们所引用的字段。
User模型 foreignKey:Refer指定User模型在user_profiles连接表中使用的外键字段应该基于User模型的Refer字段。 joinForeignKey:UserReferID指定连接表中代表User模型的外键字段名称为UserReferID。 References:UserRefer这似乎是一个笔误或误解。基于上下文它应该是用来指定foreignKey引用User模型中的哪个字段但Refer已被作为foreignKey所以这里可能是要表达foreignKey对应的实际字段是Refer。
Profile模型 joinReferences:ProfileRefer指定joinForeignKey在Profile模型中引用的字段。但示例中没有直接展示joinForeignKey的定义从上下文推测joinForeignKey可能是通过gorm:many2many:user_profiles;在User模型中定义的joinForeignKey:UserReferID对应的另一边意味着ProfileRefer应该是user_profiles表中的列名指向Profile模型。
连接表user_profiles foreign key: user_refer_id, reference: users.refer表示user_profiles表中的user_refer_id列是外键它引用users表中的refer列。 foreign key: profile_refer, reference: profiles.user_refer表示user_profiles表中的profile_refer列是外键它引用profiles表中的user_refer列。
注意事项 唯一索引Unique Index某些数据库要求只能在具有唯一索引的字段上创建外键。这就意味着如果你打算在迁移时创建外键那么被引用的字段如Refer和UserRefer需要被标记为唯一索引这在GORM中可以通过gorm:index:,unique标签来实现。
自引用 Many2Many
type User struct {gorm.ModelFriends []*User gorm:many2many:user_friends
}// 会创建连接表user_friends
// foreign key: user_id, reference: users.id
// foreign key: friend_id, reference: users.id
解读 这段内容说明了如何在使用GORM时定义一个自引用的Many To Many关系具体示例为用户与其朋友之间的关系。在这个例子中User模型通过一个名为user_friends的连接表来实现用户之间的多对多朋友关系。这意味着每个用户可以有多个朋友而每个朋友也可以同时被多个用户标记为朋友。
User模型 User模型包含了一个Friends字段这是一个指向User类型的切片。这个字段使用gorm:many2many:user_friends标签来声明一个多对多关系并指定user_friends作为连接表。
连接表user_friends 连接表user_friends用于存储用户之间朋友关系的信息。它包含两个外键字段user_id和friend_id。 user_id作为外键指向users表的id字段表示在这个朋友关系中的一个用户。 friend_id同样作为外键也指向users表的id字段但表示在这个关系中的另一个用户即朋友。 这个设计允许每条记录在user_friends表中唯一地标识一对朋友关系其中user_id和friend_id分别代表这对关系中的两个用户。值得注意的是由于这是自引用关系user_id和friend_id都引用同一个表users表的id字段。
自引用的Many To Many关系的特点 对称性在现实世界中如果用户A是用户B的朋友那么用户B通常也是用户A的朋友。然而在数据库层面这种对称性需要通过在user_friends表中为每对朋友关系添加两条记录来手动维护除非应用逻辑层提供了处理这一点的机制。 灵活性这种模型设计极大地增加了数据库模型的灵活性允许用户动态地添加或删除朋友关系。 查询查询一个用户的所有朋友涉及到连接表的自连接查询这可能比直接的一对多或一对一关系更复杂一些。
预加载
GORM可以通过Preload预加载has many关联的记录。
自定义连接表
连接表可以说一个全功能的模型支持soft Delete、钩子、更多字段就根其他模型一样。您可以通过SetupJoinTable指定它例如 注意自定义连接表要求外键是复合主键或复合唯一索引
type Person struct {ID intName stringAddresses []Address gorm:many2many:person_addresses;
}type Address struct {ID uintName string
}type PersonAddress struct {PersonID int gorm:primaryKeyAddressID int gorm:primaryKeyCreatedAt time.TimeDeletedAt gorm.DeletedAt
}func (PersonAddress) BeforeCreate(db *gorm.DB) error {// ...
}// 修改 Person 的 Addresses 字段的连接表为 PersonAddress
// PersonAddress 必须定义好所需的外键否则会报错
err : db.SetupJoinTable(Person{}, Addresses, PersonAddress{})
解读 这段内容解释了在GORM中如何自定义Many To Many关系的连接表并且如何为这个连接表添加额外的字段和功能比如软删除Soft Delete和钩子Hooks。通过这种方式连接表不仅仅是用于存储两个模型之间关系的简单表而是可以成为一个全功能的模型类似于其他的GORM模型。
自定义连接表的模型定义 Person模型 Person模型定义了一个Addresses字段通过gorm:many2many:person_addresses;标签指明和Address模型之间的多对多关系并且指定使用person_addresses作为连接表。
Address模型 Address模型是简单的包含ID和Name字段。
PersonAddress连接表模型 PersonAddress是自定义的连接表模型除了包含表示关系的PersonID和AddressID作为复合主键之外还添加了CreatedAt和DeletedAt字段。DeletedAt字段支持GORM的软删除功能。 PersonAddress模型也可以定义方法如BeforeCreate钩子这在GORM中用于在创建记录之前自动执行特定逻辑。
自定义连接表的设置 通过db.SetupJoinTable(Person{}, “Addresses”, PersonAddress{})调用GORM被指示使用PersonAddress作为Person和Address之间关系的连接表。这允许开发者利用GORM的高级功能比如钩子和软删除在连接表上添加更多的字段。
注意事项 外键要求自定义连接表要求外键是复合主键或复合唯一索引。这意味着在PersonAddress模型中PersonID和AddressID需要被标记为primaryKey以确保每个关系在表中是唯一的。
软删除通过在连接表模型中添加DeletedAt字段可以为连接表记录实现软删除功能。这意味着删除操作会更新DeletedAt字段而不是从数据库中物理删除记录允许你保留和查询被标记为删除的关系。
钩子如BeforeCreate允许你在创建连接表记录之前执行自定义逻辑这与其他GORM模型的行为一致。
总结 通过自定义连接表GORM提供了极大的灵活性和控制力使得开发者可以更细致地管理模型之间的多对多关系同时利用GORM提供的各种特性来增强连接表的功能。
外键约束
你可以通过标签constraint配置OnUpdate、OnDelete实现外键约束在使用GORM进行迁移时它会被创建例如
type User struct {gorm.ModelLanguages []Language gorm:many2many:user_speaks;
}type Language struct {Code string gorm:primarykeyName string
}// CREATE TABLE user_speaks (user_id integer,language_code text,PRIMARY KEY (user_id,language_code),CONSTRAINT fk_user_speaks_user FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE SET NULL ON UPDATE CASCADE,CONSTRAINT fk_user_speaks_language FOREIGN KEY (language_code) REFERENCES languages(code) ON DELETE SET NULL ON UPDATE CASCADE);
你也可以在删除记录时通过Select来删除many2many关系的记录查看Delete with Select获取详情。
复合外键
如果你的模型使用了复合主键GORM会默认启用复合外键。 你也可以覆盖默认的外键指定多个外键只需要逗号分隔那些键名例如
type Tag struct {ID uint gorm:primaryKeyLocale string gorm:primaryKeyValue string
}type Blog struct {ID uint gorm:primaryKeyLocale string gorm:primaryKeySubject stringBody stringTags []Tag gorm:many2many:blog_tags;LocaleTags []Tag gorm:many2many:locale_blog_tags;ForeignKey:id,locale;References:idSharedTags []Tag gorm:many2many:shared_blog_tags;ForeignKey:id;References:id
}// 连接表blog_tags
// foreign key: blog_id, reference: blogs.id
// foreign key: blog_locale, reference: blogs.locale
// foreign key: tag_id, reference: tags.id
// foreign key: tag_locale, reference: tags.locale// 连接表locale_blog_tags
// foreign key: blog_id, reference: blogs.id
// foreign key: blog_locale, reference: blogs.locale
// foreign key: tag_id, reference: tags.id// 连接表shared_blog_tags
// foreign key: blog_id, reference: blogs.id
// foreign key: tag_id, reference: tags.id
解读 这段内容解释了在使用GORM处理复合主键时如何定义和自定义复合外键关系。复合主键是指使用两个或更多的列来唯一标识表中的每行记录。当模型使用复合主键时GORM默认启用复合外键来匹配这些复合主键。然而GORM也提供了灵活性来覆盖这些默认行为允许指定自定义的外键组合。
复合主键与复合外键 在提供的例子中Tag和Blog模型都使用了复合主键ID和Locale这意味着每个Tag和Blog的唯一性不仅仅由ID决定还需要Locale来共同确定。
自定义外键关系 Blog模型的Tags字段 默认行为对于Tags字段GORM默认使用模型的复合主键ID和Locale作为复合外键。这意味着在blog_tags连接表中会有四个外键blog_id和blog_locale用来引用Blog模型tag_id和tag_locale用来引用Tag模型。
Blog模型的LocaleTags字段 自定义外键通过ForeignKey:id,locale;References:id标签明确指定了使用Blog的ID和Locale作为外键并且指定它们引用Tag模型的ID字段。这里似乎有一个小错误或遗漏因为References应该指向Tag模型的ID和Locale字段来正确映射复合外键。理论上正确的标签可能是ForeignKey:id,locale;References:id,locale。
Blog模型的SharedTags字段 简化的外键关系SharedTags字段示例通过ForeignKey:id;References:id标签只使用ID字段作为外键和引用。这在shared_blog_tags连接表中创建了一个简化的关系只包括blog_id和tag_id没有考虑Locale这可能用于那些Locale不是区分共享标签重要因素的场景。
连接表的结构 blog_tags这个连接表包含了所有四个外键完整地表示了Blog和Tag之间复合主键的多对多关系。 locale_blog_tags这个连接表应该包含了Blog和Tag之间特定于语言的关联但示例中的标签定义可能有误理应包含Locale的映射。 shared_blog_tags仅基于ID的简化多对多关系适用于跨语言共享的标签。
总结 通过这种方法GORM提供了灵活的方式来定义和自定义复合外键以及如何在多对多关系中使用它们。这使得开发者可以根据具体需求精确控制数据库关系的结构尤其是在涉及复合主键时。然而在自定义外键和引用时需要小心确保标签的正确性和一致性以避免错误和混淆。