相关文章推荐
飘逸的鞭炮  ·  如果计算机在任务时关闭,则重新启动时可能无法 ...·  1 年前    · 
豪气的人字拖  ·  WPS Excel怎么把竖排变成横排-百度经验·  2 年前    · 
聪明伶俐的领带  ·  谷歌浏览器如何才能双击关闭标签页?手把手教学 ...·  2 年前    · 
迷茫的手术刀  ·  【程序猿硬核科普】Chrome控制台的基本操 ...·  2 年前    · 
Code  ›  Gorm之关联_gorm 外键
string 关系模型 外键 主键约束
https://blog.csdn.net/qq_53267860/article/details/125370840
爱搭讪的木瓜
1 年前
  • Gorm之关联
    • Belongs To
      • 重写外键
      • 重写引用
      • Belongs to 的 CRUD
      • 预加载
      • 外键约束
    • Has One
      • 重写外键
      • 重写引用
      • 多态关联
      • Has One 的 CURD
      • 预加载
      • 自引用 Has One
      • 外键约束
    • Has Many
      • 重写外键
      • 重写引用
      • 多态关联
      • Has Many 的 CURD
      • 预加载
      • 自引用 Has Many
      • 外键约束
    • Many To Many
      • 反向引用
      • 重写外键
      • 自引用 Many2Many
      • 预加载
      • Many2Many 的 CURD
      • 自定义连接表
      • 外键约束
      • 复合外键
    • 实体关联
      • 自动创建、更新
      • 跳过自动创建、更新
      • Select/Omit 关联字段
      • 关联模式
        • 查找关联
        • 添加关联
        • 替换关联
        • 删除关联
        • 清空关联
        • 关联计数
        • 批量处理数据
      • 带 Select 的删除
      • 关联标签
    • 预加载
      • Joins 预加载
      • 预加载全部
      • 带条件的预加载
      • 自定义预加载 SQL
      • 嵌套预加载

      Belongs To

      belongs to 会与另一个模型建立了一对一的连接。 这种模型的每一个实例都“属于”另一个模型的一个实例。

      例如,您的应用包含 user 和 company,并且每个 user 能且只能被分配给一个 company。下面的类型就表示这种关系。 注意,在 User 对象中,有一个和 Company 一样的 CompanyID 。 默认情况下, CompanyID 被隐含地用来在 User 和 Company 之间创建一个外键关系, 因此必须包含在 User 结构体中才能填充 Company 内部结构体。

      // `User` 属于 `Company`,`CompanyID` 是外键
      type User struct {
        gorm.Model
        Name      string
        CompanyID int
        Company   Company
      type Company struct {
        ID   int
        Name string
      

      请参阅 预加载 以了解内部结构的详细信息。

      要定义一个 belongs to 关系,数据库的表中必须存在外键。默认情况下,外键的名字,使用拥有者的类型名称加上表的主键的字段名字

      例如,定义一个User实体属于Company实体,那么外键的名字一般使用CompanyID。

      GORM同时提供自定义外键名字的方式,如下例所示。

      type User struct {
        gorm.Model
        Name         string
        CompanyRefer int
        Company      Company `gorm:"foreignKey:CompanyRefer"`
        // 使用 CompanyRefer 作为外键
      type Company struct {
        ID   int
        Name string
      

      对于 belongs to 关系,GORM 通常使用数据库表,主表(拥有者)的主键值作为外键参考。 正如上面的例子,我们使用主表Company中的主键字段ID作为外键的参考值。

      如果在Company实体中设置了User实体,那么GORM会自动把Company中的ID属性保存到User的CompanyID属性中。

      同样的,您也可以使用标签 references 来更改它,例如:

      type User struct {
        gorm.Model
        Name      string
        CompanyID string
        Company   Company `gorm:"references:Code"` // 使用 Code 作为引用
      type Company struct {
        ID   int
        Code string
        Name string
      

      Belongs to 的 CRUD

      点击 关联模式 链接获取 belongs to 相关的用法

      GORM允许通过使用Preload或者Joins来主动加载实体的关联关系,具体内容请参考,预加载(主动加载)

      你可以通过OnUpdate, OnDelete配置标签来增加关联关系的级联操作,如下面的例子,通过GORM可以完成用户和公司的级联更新和级联删除操作:

      type User struct {
        gorm.Model
        Name      string
        CompanyID int
        Company   Company `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
      type Company struct {
        ID   int
        Name string
      

      Has One

      has one 与另一个模型建立一对一的关联,但它和一对一关系有些许不同。 这种关联表明一个模型的每个实例都包含或拥有另一个模型的一个实例。

      例如,您的应用包含 user 和 credit card 模型,且每个 user 只能有一张 credit card。

      // User 有一张 CreditCard,UserID 是外键
      type User struct {
        gorm.Model
        CreditCard CreditCard
      type CreditCard struct {
        gorm.Model
        Number string
        UserID uint
      

      对于 has one 关系,同样必须存在外键字段。拥有者将把属于它的模型的主键保存到这个字段。

      这个字段的名称通常由 has one 模型的类型加上其 主键 生成,对于上面的例子,它是 UserID。

      为 user 添加 credit card 时,它会将 user 的 ID 保存到自己的 UserID 字段。

      如果你想要使用另一个字段来保存该关系,你同样可以使用标签 foreignKey 来更改它,例如:

      type User struct {
        gorm.Model
        CreditCard CreditCard `gorm:"foreignKey:UserName"`
        // 使用 UserName 作为外键
      type CreditCard struct {
        gorm.Model
        Number   string
        UserName string
      

      默认情况下,拥有者实体会将 has one 对应模型的主键保存为外键,您也可以修改它,用另一个字段来保存,例如下个这个使用 Name 来保存的例子。

      您可以使用标签 references 来更改它,例如:

      type User struct {
        gorm.Model
        Name       string     `gorm:"index"`
        CreditCard CreditCard `gorm:"foreignkey:UserName;references:name"`
      type CreditCard struct {
        gorm.Model
        Number   string
        UserName string
      

      GORM 为 has one 和 has many 提供了多态关联支持,它会将拥有者实体的表名、主键值都保存到多态类型的字段中。

      type Cat struct {
        ID    int
        Name  string
        Toy   Toy `gorm:"polymorphic:Owner;"`
      type Dog struct {
        ID   int
        Name string
        Toy  Toy `gorm:"polymorphic:Owner;"`
      type Toy struct {
        ID        int
        Name      string
        OwnerID   int
        OwnerType string
      db.Create(&Dog{Name: "dog1", Toy: Toy{Name: "toy1"}})
      // INSERT INTO `dogs` (`name`) VALUES ("dog1")
      // INSERT INTO `toys` (`name`,`owner_id`,`owner_type`) VALUES ("toy1","1","dogs")
      

      您可以使用标签 polymorphicValue 来更改多态类型的值,例如:

      type Dog struct {
        ID   int
        Name string
        Toy  Toy `gorm:"polymorphic:Owner;polymorphicValue:master"`
      type Toy struct {
        ID        int
        Name      string
        OwnerID   int
        OwnerType string
      db.Create(&Dog{Name: "dog1", Toy: Toy{Name: "toy1"}})
      // INSERT INTO `dogs` (`name`) VALUES ("dog1")
      // INSERT INTO `toys` (`name`,`owner_id`,`owner_type`) VALUES ("toy1","1","master")
      

      Has One 的 CURD

      查看 关联模式 获取 has one 相关的用法

      GORM 可以通过 Preload、Joins 预加载 has one 关联的记录,查看 预加载 获取详情

      自引用 Has One

      type User struct {
        gorm.Model
        Name      string
        ManagerID *uint
        Manager   *User
      

      你可以通过为标签 constraint 配置 OnUpdate、OnDelete 实现外键约束,在使用 GORM 进行迁移时它会被创建,例如:

      type User struct {
        gorm.Model
        CreditCard CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
      type CreditCard struct {
        gorm.Model
        Number string
        UserID uint
      

      你也可以在删除记录时通过 Select 来删除关联的记录,查看 Delete with Select 获取详情

      Has Many

      has many 与另一个模型建立了一对多的连接。 不同于 has one,拥有者可以有零或多个关联模型。

      例如,您的应用包含 user 和 credit card 模型,且每个 user 可以有多张 credit card。

      // User 有多张 CreditCard,UserID 是外键
      type User struct {
        gorm.Model
        CreditCards []CreditCard
      type CreditCard struct {
        gorm.Model
        Number string
        UserID uint
      

      要定义 has many 关系,同样必须存在外键。 默认的外键名是拥有者的类型名加上其主键字段名

      例如,要定义一个属于 User 的模型,则其外键应该是 UserID。

      此外,想要使用另一个字段作为外键,您可以使用 foreignKey 标签自定义它:

      type User struct {
        gorm.Model
        CreditCards []CreditCard `gorm:"foreignKey:UserRefer"`
      type CreditCard struct {
        gorm.Model
        Number    string
        UserRefer uint
      

      GORM 通常使用拥有者的主键作为外键的值。 对于上面的例子,它是 User 的 ID 字段。

      为 user 添加 credit card 时,GORM 会将 user 的 ID 字段保存到 credit card 的 UserID 字段。

      同样的,您也可以使用标签 references 来更改它,例如:

      type User struct {
        gorm.Model
        MemberNumber string
        CreditCards  []CreditCard `gorm:"foreignKey:UserNumber;references:MemberNumber"`
      type CreditCard struct {
        gorm.Model
        Number     string
        UserNumber string
      

      GORM 为 has one 和 has many 提供了多态关联支持,它会将拥有者实体的表名、主键都保存到多态类型的字段中。

      type Dog struct {
        ID   int
        Name string
        Toys []Toy `gorm:"polymorphic:Owner;"`
      type Toy struct {
        ID        int
        Name      string
        OwnerID   int
        OwnerType 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")
      

      您可以使用标签 polymorphicValue 来更改多态类型的值,例如:

      type Dog struct {
        ID   int
        Name string
        Toys []Toy `gorm:"polymorphic:Owner;polymorphicValue:master"`
      type Toy struct {
        ID        int
        Name      string
        OwnerID   int
        OwnerType 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")
      

      Has Many 的 CURD

      查看 关联模式 获取 has many 相关的用法

      GORM 可以通过 Preload 预加载 has many 关联的记录,查看 预加载 获取详情

      自引用 Has Many

      type User struct {
        gorm.Model
        Name      string
        ManagerID *uint
        Team      []User `gorm:"foreignkey:ManagerID"`
      

      你可以通过为标签 constraint 配置 OnUpdate、OnDelete 实现外键约束,在使用 GORM 进行迁移时它会被创建,例如:

      type User struct {
        gorm.Model
        CreditCards []CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
      type CreditCard struct {
        gorm.Model
        Number string
        UserID uint
      

      你也可以在删除记录时通过 Select 来删除 has many 关联的记录,查看 Delete with Select 获取详情

      Many To Many

      Many to Many 会在两个 model 中添加一张连接表。

      例如,您的应用包含了 user 和 language,且一个 user 可以说多种 language,多个 user 也可以说一种 language。

      // User 拥有并属于多种 language,`user_languages` 是连接表
      type User struct {
        gorm.Model
        Languages []Language `gorm:"many2many:user_languages;"`
      type Language struct {
        gorm.Model
        Name string
      

      当使用 GORM 的 AutoMigrate 为 User 创建表时,GORM 会自动创建连接表

      // User 拥有并属于多种 language,`user_languages` 是连接表
      type User struct {
        gorm.Model
        Languages []*Language `gorm:"many2many:user_languages;"`
      type Language struct {
        gorm.Model
        Name string
        Users []*User `gorm:"many2many:user_languages;"`
      

      对于 many2many 关系,连接表会同时拥有两个模型的外键,例如:

      type User struct {
        gorm.Model
        Languages []Language `gorm:"many2many:user_languages;"`
      type Language struct {
        gorm.Model
        Name string
      // 连接表:user_languages
      //   foreign key: user_id, reference: users.id
      //   foreign key: language_id, reference: languages.id
      

      若要重写它们,可以使用标签 foreignKey、references、joinforeignKey、joinReferences。当然,您不需要使用全部的标签,你可以仅使用其中的一个重写部分的外键、引用。

      type User struct {
          gorm.Model
          Profiles []Profile `gorm:"many2many:user_profiles;foreignKey:Refer;joinForeignKey:UserReferID;References:UserRefer;joinReferences:ProfileRefer"`
          Refer    uint      `gorm:"index:,unique"`
      type Profile struct {
          gorm.Model
          Name      string
          UserRefer uint `gorm:"index:,unique"`
      // 会创建连接表:user_profiles
      //   foreign key: user_refer_id, reference: users.refer
      //   foreign key: profile_refer, reference: profiles.user_refer
       

      注意: 某些数据库只允许在唯一索引字段上创建外键,如果您在迁移时会创建外键,则需要指定 unique index 标签。

      自引用 Many2Many

      自引用 many2many 关系

      type User struct {
        gorm.Model
          Friends []*User `gorm:"many2many:user_friends"`
      // 会创建连接表:user_friends
      //   foreign key: user_id, reference: users.id
      //   foreign key: friend_id, reference: users.id
      

      GORM 可以通过 Preload 预加载 has many 关联的记录,查看 预加载 获取详情

      Many2Many 的 CURD

      查看 关联模式 获取 many2many 相关的用法

      自定义连接表

      连接表 可以是一个全功能的模型,支持 Soft Delete、钩子、更多的字段,就跟其它模型一样。您可以通过 SetupJoinTable 指定它,例如:

      注意: 自定义连接表要求外键是复合主键或复合唯一索引

      type Person struct {
        ID        int
        Name      string
        Addresses []Address `gorm:"many2many:person_addresses;"`
      type Address struct {
        ID   uint
        Name string
      type PersonAddress struct {
        PersonID  int `gorm:"primaryKey"`
        AddressID int `gorm:"primaryKey"`
        CreatedAt time.Time
        DeletedAt gorm.DeletedAt
      func (PersonAddress) BeforeCreate(db *gorm.DB) error {
        // ...
      // 修改 Person 的 Addresses 字段的连接表为 PersonAddress
      // PersonAddress 必须定义好所需的外键,否则会报错
      err := db.SetupJoinTable(&Person{}, "Addresses", &PersonAddress{})
      

      你可以通过为标签 constraint 配置 OnUpdate、OnDelete 实现外键约束,在使用 GORM 进行迁移时它会被创建,例如:

      type User struct {
        gorm.Model
        Languages []Language `gorm:"many2many:user_speaks;"`
      type Language struct {
        Code string `gorm:"primarykey"`
        Name 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:"primaryKey"`
        Locale string `gorm:"primaryKey"`
        Value  string
      type Blog struct {
        ID         uint   `gorm:"primaryKey"`
        Locale     string `gorm:"primaryKey"`
        Subject    string
        Body       string
        Tags       []Tag `gorm:"many2many:blog_tags;"`
        LocaleTags []Tag `gorm:"many2many:locale_blog_tags;ForeignKey:id,locale;References:id"`
        SharedTags []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 会通过 Upsert 自动保存关联及其引用记录。

      user := User{
        Name:            "jinzhu",
        BillingAddress:  Address{Address1: "Billing Address - Address 1"},
        ShippingAddress: Address{Address1: "Shipping Address - Address 1"},
        Emails:          []Email{
          {Email: "jinzhu@example.com"},
          {Email: "jinzhu-2@example.com"},
        Languages:       []Language{
          {Name: "ZH"},
          {Name: "EN"},
      db.Create(&user)
      // BEGIN TRANSACTION;
      // INSERT INTO "addresses" (address1) VALUES ("Billing Address - Address 1"), ("Shipping Address - Address 1") ON DUPLICATE KEY DO NOTHING;
      // INSERT INTO "users" (name,billing_address_id,shipping_address_id) VALUES ("jinzhu", 1, 2);
      // INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu@example.com"), (111, "jinzhu-2@example.com") ON DUPLICATE KEY DO NOTHING;
      // INSERT INTO "languages" ("name") VALUES ('ZH'), ('EN') ON DUPLICATE KEY DO NOTHING;
      // INSERT INTO "user_languages" ("user_id","language_id") VALUES (111, 1), (111, 2) ON DUPLICATE KEY DO NOTHING;
      // COMMIT;
      db.Save(&user)
      

      如果您想要更新关联的数据,您应该使用 FullSaveAssociations 模式:

      db.Session(&gorm.Session{FullSaveAssociations: true}).Updates(&user)
      // ...
      // INSERT INTO "addresses" (address1) VALUES ("Billing Address - Address 1"), ("Shipping Address - Address 1") ON DUPLICATE KEY SET address1=VALUES(address1);
      // INSERT INTO "users" (name,billing_address_id,shipping_address_id) VALUES ("jinzhu", 1, 2);
      // INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu@example.com"), (111, "jinzhu-2@example.com") ON DUPLICATE KEY SET email=VALUES(email);
      // ...
      

      跳过自动创建、更新

      若要在创建、更新时跳过自动保存,您可以使用 Select 或 Omit,例如:

      user := User{
        Name:            "jinzhu",
        BillingAddress:  Address{Address1: "Billing Address - Address 1"},
        ShippingAddress: Address{Address1: "Shipping Address - Address 1"},
        Emails:          []Email{
          {Email: "jinzhu@example.com"},
          {Email: "jinzhu-2@example.com"},
        Languages:       []Language{
          {Name: "ZH"},
          {Name: "EN"},
      db.Select("Name").Create(&user)
      // INSERT INTO "users" (name) VALUES ("jinzhu", 1, 2);
      db.Omit("BillingAddress").Create(&user)
      // Skip create BillingAddress when creating a user
      db.Omit(clause.Associations).Create(&user)
      // Skip all associations when creating a user
       

      NOTE: 对于 many2many 关联,GORM 在创建连接表引用之前,会先 upsert 关联。如果你想跳过关联的 upsert,你可以这样做:

      db.Omit("Languages.*").Create(&user)
       

      下面的代码将跳过创建关联及其引用

      db.Omit("Languages").Create(&user)
      

      Select/Omit 关联字段

      user := User{
        Name:            "jinzhu",
        BillingAddress:  Address{Address1: "Billing Address - Address 1", Address2: "addr2"},
        ShippingAddress: Address{Address1: "Shipping Address - Address 1", Address2: "addr2"},
      // 创建 user 及其 BillingAddress、ShippingAddress
      // 在创建 BillingAddress 时,仅使用其 address1、address2 字段,忽略其它字段
      db.Select("BillingAddress.Address1", "BillingAddress.Address2").Create(&user)
      db.Omit("BillingAddress.Address2", "BillingAddress.CreatedAt").Create(&user)
      

      关联模式包含一些在处理关系时有用的方法

      // 开始关联模式
      var user User
      db.Model(&user).Association("Languages")
      // `user` 是源模型,它的主键不能为空
      // 关系的字段名是 `Languages`
      // 如果匹配了上面两个要求,会开始关联模式,否则会返回错误
      db.Model(&user).Association("Languages").Error
      

      查找所有匹配的关联记录

      db.Model(&user).Association("Languages").Find(&languages)
      

      查找带条件的关联

      codes := []string{"zh-CN", "en-US", "ja-JP"}
      db.Model(&user).Where("code IN ?", codes).Association("Languages").Find(&languages)
      db.Model(&
      
      
      
      
          
      user).Where("code IN ?", codes).Order("code desc").Association("Languages").Find(&languages)
      

      为 many to many、has many 添加新的关联;为 has one, belongs to 替换当前的关联

      db.Model(&user).Association("Languages").Append([]Language{languageZH, languageEN})
      db.Model(&user).Association("Languages").Append(&Language{Name: "DE"})
      db.Model(&user).Association("CreditCard").Append(&CreditCard{Number: "411111111111"})
      

      用一个新的关联替换当前的关联

      db.Model(&user).Association("Languages").Replace([]Language{languageZH, languageEN})
      db.Model(&user).Association("Languages").Replace(Language{Name: "DE"}, languageEN)
      

      如果存在,则删除源模型与参数之间的关系,只会删除引用,不会从数据库中删除这些对象。

      db.Model(&user).Association("Languages").Delete([]Language{languageZH, languageEN})
      db.Model(&user).Association("Languages").Delete(languageZH, languageEN)
      

      删除源模型与关联之间的所有引用,但不会删除这些关联

      db.Model(&user).Association("Languages").Clear()
      

      返回当前关联的计数

      db.Model(&user).Association("Languages").Count()
      // 条件计数
      codes := []string{"zh-CN", "en-US", "ja-JP"}
      db.Model(&user).Where("code IN ?", codes).Association("Languages").Count()
      
      批量处理数据

      关联模式也支持批量处理,例如:

      // 查询所有用户的所有角色
      db.Model(&users).Association("Role").Find(&roles)
      // 从所有 team 中删除 user A
      db.Model(&users).Association("Team").Delete(&userA)
      // 获取去重的用户所属 team 数量
      db.Model(&users).Association("Team").Count()
      // 对于批量数据的 `Append`、`Replace`,参数的长度必须与数据的长度相同,否则会返回 error
      var users = []User{user1, user2, user3}
      // 例如:现在有三个 user,Append userA 到 user1 的 team,Append userB 到 user2 的 team,Append userA、userB 和 userC 到 user3 的 team
      db.Model(&users).Association("Team").Append(&userA, &userB, &[]User{userA, userB, userC})
      // 重置 user1 team 为 userA,重置 user2 的 team 为 userB,重置 user3 的 team 为 userA、 userB 和 userC
      db.Model(&users).Association("Team").Replace(&userA, &userB, &[]User{userA, userB, userC})
      

      带 Select 的删除

      你可以在删除记录时通过 Select 来删除具有 has one、has many、many2many 关系的记录,例如:

      // 删除 user 时,也删除 user 的 account
      db.Select("Account").Delete(&user)
      // 删除 user 时,也删除 user 的 Orders、CreditCards 记录
      db.Select("Orders", "CreditCards").Delete(&user)
      // 删除 user 时,也删除用户所有 has one/many、many2many 记录
      db.Select(clause.Associations).Delete(&user)
      // 删除 users 时,也删除每一个 user 的 account
      db.Select("Account").Delete(&users)
       

      NOTE: Associations will only be deleted if the deleting records’s primary key is not zero, GORM will use those primary keys as conditions to delete selected associations

      // DOESN'T WORK
      db.Select("Account").Where("name = ?", "jinzhu").Delete(&User{})
      // 会删除所有 name=`jinzhu` 的 user,但这些 user 的 account 不会被删除
      db.Select("Account").Where("name = ?", "jinzhu"
      
      
      
      
          
      ).Delete(&User{ID: 1})
      // 会删除 name = `jinzhu` 且 id = `1` 的 user,并且 user `1` 的 account 也会被删除
      db.Select("Account").Delete(&User{ID: 1})
      // 会删除 id = `1` 的 user,并且 user `1` 的 account 也会被删除
      
      标签描述
      foreignKey指定当前模型的列作为连接表的外键
      references指定引用表的列名,其将被映射为连接表外键
      polymorphic指定多态类型,比如模型名
      polymorphicValue指定多态值、默认表名
      many2many指定连接表表名
      joinForeignKey指定连接表的外键列名,其将被映射到当前表
      joinReferences指定连接表的外键列名,其将被映射到引用表
      constraint关系约束,例如:OnUpdate、OnDelete

      GORM 允许在 Preload 的其它 SQL 中直接加载关系,例如:

      type User struct {
        gorm.Model
        Username string
        Orders   []Order
      type Order struct {
        gorm.Model
        UserID uint
        Price  float64
      // 查找 user 时预加载相关 Order
      db.Preload("Orders").Find(&users)
      // SELECT * FROM users;
      // SELECT * FROM orders WHERE user_id IN (1,2,3,4);
      db.Preload("Orders").Preload("Profile").Preload("Role").Find(&users)
      // SELECT * FROM users;
      // SELECT * FROM orders WHERE user_id IN (1,2,3,4); // has many
      // SELECT * FROM profiles WHERE user_id IN (1,2,3,4); // has one
      // SELECT * FROM roles WHERE id IN (4,5,6); // belongs to
      

      Joins 预加载

      Preload 在一个单独查询中加载关联数据。而 Join Preload 会使用 inner join 加载关联数据,例如:

      db.Joins("Company").Joins("Manager").Joins("Account").First(&user, 1)
      db.Joins("Company").Joins("Manager").Joins("Account").First(&user, "users.name = ?", "jinzhu")
      db.Joins("Company").Joins("Manager").Joins("Account").Find(&users, "users.id IN ?", []int{1,2,3,4,5})
      

      带条件的 Join

      db.Joins("Company", DB.Where(&Company{Alive: true})).Find(&users)
      // SELECT `users`.`id`,`users`.`name`,`users`.`age`,`Company`.`id` AS `Company__id`,`Company`.`name` AS `Company__name` FROM `users` LEFT JOIN `companies` AS `Company` ON `users`.`company_id` = `Company`.`id` AND `Company`.`alive` = true;
       

      注意 Join Preload 适用于一对一的关系,例如: has one, belongs to

      预加载全部

      与创建、更新时使用 Select 类似,clause.Associations 也可以和 Preload 一起使用,它可以用来 预加载 全部关联,例如:

      type User struct {
        gorm.Model
        Name       string
        CompanyID  uint
        Company    Company
        Role       Role
        Orders     []Order
      db.Preload(clause.Associations).Find(&users)
      

      clause.Associations 不会预加载嵌套的关联,但你可以使用嵌套预加载 例如:

      db.Preload("Orders.OrderItems.Product").Preload(clause.Associations).Find(&users)
      

      带条件的预加载

      GORM 允许带条件的 Preload 关联,类似于内联条件

      // 带条件的预加载 Order
      db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
      // SELECT * FROM users;
      // SELECT * FROM orders WHERE user_id IN (1,2,3,4) AND state NOT IN ('cancelled');
      db.Where("state = ?", "active").Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
      // SELECT * FROM users WHERE state = 'active';
      // SELECT * FROM orders WHERE user_id IN (1,2) AND state NOT IN ('cancelled');
      

      自定义预加载 SQL

      您可以通过 func(db *gorm.DB) *gorm.DB 实现自定义预加载 SQL,例如:

      db.Preload("Orders", func(db *gorm.DB) *gorm.DB {
        return db.Order("orders.amount DESC")
      }).Find(&users)
      // SELECT * FROM users;
      // SELECT * FROM orders WHERE user_id IN (1,2,3,4) order by orders.amount DESC;
      

      嵌套预加载

      GORM 支持嵌套预加载,例如:

      db.Preload("Orders.OrderItems.Product").Preload("CreditCard").Find(&users)
      // 自定义预加载 `Orders` 的条件
      // 这样,GORM 就不会加载不匹配的 order 记录
      db.Preload("Orders", "state = ?", "paid").Preload("Orders.OrderItems").Find(&users)
                                          user_topic表里的id,关联topic_image表里的topicID,
      //用户在发表话题动态的时候,同时发了多张照片,
      //查询的时候需要从topic_image表查出用户此条动态发布的所有照片。
      //是这样子的一对多关系
      1.model字段部分(加外键关联外键)
      type UserTopic struct {
      	ID         int64 `gorm:"primary_key" json:"id"`
      	UserID             int64             `json:"user_id"`
      	TopicImgURL        string      
      上下文,准备语句模式,DryRun模式
      批处理插入,FindIn批处理,查找地图
      SQL Builder,Upsert,锁定,优化器/索引/注释提示,NamedArg,使用SQL Expr搜索/更新/创建
      可扩展的灵活插件API:数据库解析器(多个数据库,读/写拆分)/ Prometheus…
                                          我们再聊一聊gorm自动迁移数据库:AutoMigrate()当数据库迁移时,若方法中有从表,gorm是会自动将依赖的主表创建出来的,(多对多关系不会)所以迁移表时,只需要将最从表放入,其他主表都会自动创建。同时也可以认证表与表之间的关系我期待中的表关系如下: 但实际是  我辛辛苦苦写了那么多的tag,都没起作用???可都是去介绍手动创建外键:AddForeignKey() (5条消息) gorm标签外键失效_鹿灏楷silves的博客-CSDN博客可能跟我出错的原因并不一致。居然可以创建出来表的关系。得出结
                                          在 设置外键的时候不是只将字段和要关联的外键的结构体对应上就可以了, 还需要写一个关联的字段id 如:
      type Blog struct {
      	ID        uint `gorm:"primary_key"`
      	Title string `gorm:"not null;size:256"`
      	Content string `gorm:"type:text;not null"`
      	ShowContent string `gorm:"not null"`
      	LookNum int `gorm:"defau
      1、事务的隔离级别
      由低到高依次为Read uncommitted(未授权读取、读未提交)、Read committed(授权读取、读提交)、Repeatable read(可重复读取)、Serializable(序列化),这四个级别可以逐个解决脏读、不可...
      官方文档看起来很容易误导,让开发以为一对多的关系就必须要存在外键,但是我们再真实的开发环境下,大多是不会用到数据库中的物理外键的,仅仅只是做一个逻辑关联就够了.官方文档这里说的必须存在外键是我们再model里面必须要指明外键,而不是数据库中一定要有这个外键,
      注意: 这种情况我们就不能使用db.AutoMigrate() 来自动创建表了,因为我们再代码中指明外键,如果再使用
      db.AutoMi
                                          belongs to 关联建立一个和另一个模型的一对一连接,使得模型声明每个实例都「属于」另一个模型的一个实例 。例如,如果你的应用包含了用户和用户资料, 并且每一个用户资料只分配给一个用户
      为了定义从属关系, 外键是必须存在的, 默认的外键使用所有者类型名称加上其主键。像上面的例子,为了声明一个模型属于 User,它的外键应该为 UserID。GORM 提供了一个定制外键的方法,例如:
      关联外键
      对于从属关系, GORM 通常使用所有者的主键作为外键值,在上面的例子中,就是 User 的 ID。当你
                                          gorm约定GORM倾向于约定,而不是配置。默认情况下,GORM使用ID作为主键,使用结构体名的蛇形复数作为表名,字段名的蛇形作为列名,并使用CreatedAt、UpdatedAt字段追踪创建、更新时间蛇形约定可以看到之前我们创建的struct是,而在数据库生成的表名为productsgorm.ModelGORM定义一个gorm.Model结构体,其包括字段ID、CreatedAt、UpdatedAt、DeletedAt可以自定义TAG,如gorm->主键;......
                                          GORM 是一款使用 Go 语言编写的 ORM(对象关系映射)库,它提供了一种简洁、高效、灵活的方式来操作数据库。GORM 支持多种关系型数据库,包括 MySQL、PostgreSQL、SQLite 等,同时也提供了一些高级功能,例如事务、预加载、关联查询等。
      type DtProject struct {
      	gorm.Model
      	Name  string `json:"name" form:"name" gorm:"column:name;comment:;type:varchar(191);"`
      type DtProjectWorkerRel struct {
      	gorm.Model
      	ProjectId    uint   `json:"projectId" gorm:"comment:项目id;unique_inde
      
 
推荐文章
飘逸的鞭炮  ·  如果计算机在任务时关闭,则重新启动时可能无法运行计划的任务 - Windows Server | Microsoft Learn
1 年前
豪气的人字拖  ·  WPS Excel怎么把竖排变成横排-百度经验
2 年前
聪明伶俐的领带  ·  谷歌浏览器如何才能双击关闭标签页?手把手教学 - 哔哩哔哩
2 年前
迷茫的手术刀  ·  【程序猿硬核科普】Chrome控制台的基本操作 | 谷歌浏览器控制台格式错乱解决方法-腾讯云开发者社区-腾讯云
2 年前
今天看啥   ·   Py中国   ·   codingpro   ·   小百科   ·   link之家   ·   卧龙AI搜索
删除内容请联系邮箱 2879853325@qq.com
Code - 代码工具平台
© 2024 ~ 沪ICP备11025650号