微网站简介,宜兴百度推广公司,超炫html5网站模板,负责网站建设推广gorm day7
gorm Belongs To关系gorm Has One关系 gorm Belongs To关系
在看文档之前先进行一些基本概念的学习#xff1a;
什么是主键#xff1f;#xff08;Primary Key) 主键是一个表中的特定列#xff08;或一组列#xff09;#xff0c;用来唯一标识表中的每一行记…gorm day7
gorm Belongs To关系gorm Has One关系 gorm Belongs To关系
在看文档之前先进行一些基本概念的学习
什么是主键Primary Key) 主键是一个表中的特定列或一组列用来唯一标识表中的每一行记录。一个表只能有一个主键。 主键的值必须是唯一的不允许为空NULL。 主键通常是表的第一个列但也可以设置为多列的组合这种情况称为复合主键。
什么是外键Foreign Key 外键是一个表中的列**它用来链接另一个表的主键**建立两个表之间的关系。 外键的值必须匹配另一个表的主键列或者是 NULL。如果是 NULL则表示没有关联的记录。 通过外键数据库可以维护表之间的数据完整性和关系约束。
例子 假设有两个表Authors 和 Books。每位作者Author可以写多本书Books但每本书只能有一个作者。这里Authors 表的 ID 字段是主键Books 表的 AuthorID 字段是外键。
CREATE TABLE Authors (ID INT PRIMARY KEY,Name VARCHAR(100)
);CREATE TABLE Books (ID INT PRIMARY KEY,Title VARCHAR(100),AuthorID INT,FOREIGN KEY (AuthorID) REFERENCES Authors(ID)
);
Authors 表 ID 是主键用于唯一标识每位作者。 Name 是作者的名字。
Books 表 ID 是主键用于唯一标识每本书。 Title 是书的标题。 AuthorID 是外键它引用 Authors 表的 ID 字段。这表示每本书都关联到一个作者。
关系解释 通过在 Books 表中设置 AuthorID 作为外键我们建立了 Books 和 Authors 之间的一对多关系即一个作者可以对应多本书但每本书只能对应一个作者。 如果尝试在 Books 表中插入一个 AuthorID 不存在于 Authors 表中的值数据库将拒绝这种插入操作因为这违反了外键约束。
通过使用主键和外键数据库不仅能够有效地组织和关联数据还能通过这些约束来保证数据的一致性和完整性。
GORM中的一对一关系 在 GORM 中“Belongs To” 关系表示两个模型之间的一对一关系其中一个模型拥有另一个模型的外键。这种关系通常用于表示拥有者owner和被拥有owned 实体之间的关系。 先学一个简单的例子再看文档 举例说明 假设我们有两个模型User 和 Profile其中每个 User 都有一个与之关联的 Profile。在这种情况下Profile 属于 User因为 Profile 包含指向 User 的外键。
package mainimport (gorm.io/driver/sqlitegorm.io/gormlog
)type User struct {gorm.ModelName stringProfile Profile
}type Profile struct {gorm.ModelUserID uint // 这是外键Bio string
}func main() {db, err : gorm.Open(sqlite.Open(test.db), gorm.Config{})if err ! nil {log.Fatal(failed to connect database)}// 自动迁移 schemadb.AutoMigrate(User{}, Profile{})// 创建 User 和关联的 Profileuser : User{Name: John Doe, Profile: Profile{Bio: Gopher}}db.Create(user)// 查询 User 并加载其 Profilevar queriedUser Userdb.Preload(Profile).Find(queriedUser, user.ID)log.Println(queriedUser.Name, queriedUser.Profile.Bio)
}
代码解读 模型定义User 模型有一个 Profile 字段表示每个 User 都关联一个 Profile。 Profile 模型中的 UserID 字段作为外键指向 User 模型的 ID表明每个 Profile 属于一个 User。
自动迁移AutoMigrateGORM 的 AutoMigrate 方法用来根据模型定义自动创建或更新数据库表。在这个例子中它会创建 users 和 profiles 表并确保 profiles 表有一个指向 users 表的外键 user_id。
创建记录通过 db.Create(user) 创建一个 User 实例和与之关联的 Profile 实例。GORM 会自动处理外键关系并在数据库中正确插入记录。
查询并加载关联db.Preload(“Profile”).Find(queriedUser, user.ID) 查询指定的 User 并预加载Preload其关联的 Profile。Preload 使得在查询 User 的同时也自动加载其 Profile避免了后续单独查询 Profile 的需要。
这里我再解读什么是预加载 预加载Preloading是 ORM对象关系映射框架中的一个概念用于自动加载数据库中的关联记录。当你查询某个实体时预加载可以同时加载与之相关联的其他实体或集合。这通常通过执行额外的查询来实现然后将结果自动填充到主查询对象的关联属性中。预加载主要用于解决“N1 查询问题”提高数据查询效率。
什么时候需要使用预加载 当你需要访问对象及其相关联对象的数据时使用预加载可以一次性加载所有需要的数据避免了多次查询数据库从而减少了数据库的访问次数和提高了应用性能。特别是在以下情况下特别有用 展示关联数据当你需要在用户界面上展示对象及其关联数据时如展示每本书及其作者信息。 避免 N1 查询问题在没有预加载的情况下如果你先查询主对象列表然后对于列表中的每个对象再去查询关联对象这将导致大量的数据库查询即 N1 查询问题。
预加载示例 假设我们有两个模型Author 和 Book每个 Author 可以有多本 Book。我们希望查询某个作者及其所有书籍。
package mainimport (gorm.io/driver/sqlitegorm.io/gormlog
)type Author struct {gorm.ModelName stringBooks []Book
}type Book struct {gorm.ModelTitle stringAuthorID uint
}func main() {db, err : gorm.Open(sqlite.Open(test.db), gorm.Config{})if err ! nil {log.Fatal(failed to connect database)}// 自动迁移 schemadb.AutoMigrate(Author{}, Book{})// 创建一个 Author 及其 Booksauthor : Author{Name: John Doe, Books: []Book{{Title: GORM Guide}, {Title: GORM Tips}}}db.Create(author)// 查询 Author 并预加载其 Booksvar queriedAuthor Authordb.Preload(Books).First(queriedAuthor, author.ID)log.Printf(Author: %v, Books: %v, queriedAuthor.Name, queriedAuthor.Books)
}
在上述代码中我们首先创建了一个 Author 记录以及关联的 Book 记录。 使用 db.Preload(“Books”).First(queriedAuthor, author.ID) 查询时GORM 不仅会加载请求的 Author还会自动加载与该 Author 关联的所有 Book 记录。 这意味着当我们访问 queriedAuthor.Books 时相关的书籍数据已经被加载好了无需再执行额外的数据库查询。
Belongs To关系总结 “Belongs To” 关系是 GORM 中表示一对一关联的一种方式它允许你在相关模型之间定义清晰的所有权关系。通过声明外键和使用 GORM 提供的方法如 Preload可以轻松管理和查询这些关联的数据。
一句话总结Belongs to咋实现的上面这个例子User就是直接包含要拥有的结构体被拥有的就通过UserID uint字段来建立关系。
这里来具体说说怎么实现 在 GORM 中遵循 表名 ID 命名约定来指定外键字段名称是一种常见做法但它不是强制性的。这种约定有助于清晰地表示外键字段是如何与另一张表的主键相关联的。然而GORM 提供了灵活的方式来自定义外键名称如果你不遵循这个约定你可以使用 GORM 的标签来明确指定外键和引用字段。
外键命名约定 默认约定对于一对一和一对多的关系如果你不显式指定外键GORM 会使用模型名称加上 ID 的形式来寻找外键。例如如果 Profile 模型属于 User 模型GORM 默认会期望在 Profile 中找到一个名为 UserID 的字段作为外键。 自定义外键如果你的外键名称不遵循默认的命名约定或者你想使用不同的字段作为外键你可以使用 GORM 的 foreignKey 标签在模型定义中明确指定。例如
type Profile struct {gorm.ModelUserRefer uint // 自定义外键字段名Bio string
}type User struct {gorm.ModelName stringProfile Profile gorm:foreignKey:UserRefer // 明确指定外键为 UserRefer
}
看好在拥有者那里声明被拥有者的外键。 对于外键字段使用 uint无符号整型是很常见的因为它对应于许多数据库自动生成的主键的数据类型如自增ID。无符号整型足以容纳大多数情况下的主键值并且避免了负数ID的可能性这在实际应用中很少见。 然而外键的具体数据类型应该与它引用的主键字段的数据类型相匹配。如果主键字段是 int 或其他类型外键字段也应该使用相同的类型以保证数据的一致性和正确的关联。 比如type Profile struct { gorm.Model UserRefer uint // 自定义外键字段名 Bio string }它的主键就在gorm.Model中是ID而且是uint类型的。
但是我觉得分析包含关系不能太公式化因为有的例子不这样。比如下面的文档例子。
gorm文档的Belongs To
现在看懂这个文档简直太简单了 belongs to会与另一个模型建立了一对一的连接。这种模型的每一个实例都属于另一个模型的实例。
例如您的应用包含user和company并且每个user能且智能被分配给一个conpany。下面的类型就表示这种关系注意在User对象中有一个和company一样的companyID。默认情况下CompanyID被隐含的用来在User和Company之间创建一个外键关系因此必须包含在User结构体中才能填充Company内部结构体。
// User 属于 CompanyCompanyID 是外键
type User struct {gorm.ModelName stringCompanyID intCompany Company
}type Company struct {ID intName string
}
例子解读 这个看起来感觉关系像单向的这里进行解读这是一个很典型的Belongs To关系。
type User struct {gorm.ModelName stringCompanyID intCompany Company
}其实这里是一种变通这里为什么CompanyID是外键还是表明ID的原理。
关系定义 User属于Company通过在User结构体中包含一个Company类型的字段我们表明了每个User都关联到一个CompanyCompanyID字段作为外键存储了对应Company记录的ID值。 如何建立关系 外键在 User 结构体中CompanyID 字段明确指出了 User 和 Company 之间的关联关系。GORM 通过这个字段知道如何在数据库中查找对应的 Company 记录。CompanyID 的值是 Company 表中某条记录的 ID 值。
没有直接的 UserID 在 Company 中在 “Belongs To” 关系中并不需要在 “拥有者”Company中定义一个指向 “被拥有者”User的字段如 UserID。这是因为关系的定义是单向的从 User 指向 Company。如果你想从 Company 访问其所有 User那是另一种关系类型—“Has Many”。
关系的单向性和双向性 单向性在这个例子中关系是单向定义的从 User 到 Company。这意味着你可以很容易地从一个 User 记录找到它所属的 Company 记录但是从 Company 记录出发并不直接知道哪些 User 属于它。
实现双向访问如果你想在 Company 模型中也能访问其所有 User 记录你可以在 Company 结构体中添加一个 User 切片并使用 GORM 的标签来指定关系
type Company struct {ID intName stringUsers []User gorm:foreignKey:CompanyID // 指定 Company 到 User 的关系
}
通过这种方式Company 模型现在包含了一个 Users 字段GORM 会自动处理这个 “Has Many” 关系允许你从 Company 实体访问所有相关的 User 实体。
总结 我之前觉得怪怪的就是没有意识到关系的单向性和双向性的问题。 在 “Belongs To” 关系中不需要在 “拥有者”Company中定义一个指向 “被拥有者”User的字段因为关系是通过 User 中的外键字段来定义的。 如果需要实现从 Company 访问 User 的双向访问可以在 Company 中添加一个指向多个 User 的切片并适当配置 GORM 标签来表示这种 “Has Many” 关系。
重写外键
要定义一个belongs to关系数据库的表中必须存在外键。默认情况下使用者的类型名称加上表的主键的字段名字例如定义一个User实体属于Company实体那么外键的名字一般使用CompanyID。 Gorm同时提供自定义外键如下例所示
type User struct {gorm.ModelName stringCompanyRefer intCompany Company gorm:foreignKey:CompanyRefer// 使用 CompanyRefer 作为外键
}type Company struct {ID intName string
}
Company Company gorm:foreignKey:CompanyRefer 这个就像是一个显示声明在 Company 字段的 GORM 标签中通过 foreignKey:CompanyRefer 明确指定了 CompanyRefer 字段作为 User 与 Company 之间关联的外键。这告诉 GORM当处理 User 和 Company 之间的关联时应该使用 CompanyRefer 字段作为外键。
效果 这种方式提供了额外的灵活性允许你根据实际的数据库设计或个人偏好来命名外键。 当你查询 User 实体并希望连同其所属的 Company 实体一起加载时GORM 会使用 CompanyRefer 字段来解析这个关系并正确地加载关联的 Company 实体。
重写引用
对于belongs to 关系GORM通常使用数据库表主表拥有者的主键值作为外键参考正如上面的例子我们使用主表Company中的主键字段ID作为外键的参考值。 如果在Company实体中设置了User实体那么GORM会自动把Company中的ID属性保存到User的Company属性中。 通用的您也可以使用标签references来更改它例如
type User struct {gorm.ModelName stringCompanyID stringCompany Company gorm:references:Code // 使用 Code 作为引用
}type Company struct {ID intCode stringName string
}
解读 这段内容描述了在 GORM 中如何自定义 “Belongs To” 关系中外键引用的字段。默认情况下GORM 使用被关联模型拥有者如 Company的主键通常是 ID 字段作为外键的参考值。然而你可以通过 references 标签指定一个不同的字段作为外键的参考。
重写引用的解释 默认引用在没有使用 references 标签的情况下GORM 会假定外键 (CompanyID 在 User 结构体中) 引用了关联模型 (Company) 的主键 (ID)。这意味着CompanyID 字段将存储对应 Company 记录的 ID 值。
自定义引用通过 references 标签你可以指定一个不同的字段作为关联的依据。在你提供的例子中Company 的 Code 字段被用作外键引用而不是默认的 ID 字段。
示例解释
type User struct {gorm.ModelName stringCompanyID string // 注意这里 CompanyID 的类型是 stringCompany Company gorm:references:Code // 使用 Company 的 Code 字段作为外键引用
}type Company struct {ID intCode string // 自定义的唯一标识符用作 User 的外键引用Name string
}
在这个例子中User 和 Company 之间的关联不再是通过 Company 的 ID 字段而是通过 Company 的 Code 字段来建立的。这意味着 User 表中的 CompanyID 字段将存储与其关联的 Company 记录的 Code 值。
可能对于上面举得这个例子你有点疑惑这里我进一步解读 通过使用 references:Code 标签我们告诉 GORM 在处理 User 和 Company 之间的关系时User 表中的 CompanyID 字段应该存储 Company 表中某条记录的 Code 值而不是通常的 ID 值。这里的 Code 值是指 Company 表中的 Code 字段它被用作连接两个表的参考值。
通常外键字段在这个例子中是 User 的 CompanyID存储的是它所引用的表的主键值。但是在这个例子中我们改变了这个行为让 CompanyID 存储的是 Company 记录的 Code 字段的值。
重点澄清 **正常情况**没有使用 references 标签时User 的 CompanyID 字段会存储一个 Company 的 ID 值作为外键连接到 Company 表。 **自定义引用**通过在 User 结构体中对 Company 字段使用 gorm:“references:Code”你告诉 GORMUser 的 CompanyID 字段应该存储对应的 Company 记录的 Code 字段的值而非 ID 字段的值。这意味着当你创建或查询 User 记录时GORM 会使用 Company 的 Code 字段值来建立关联而不是使用 ID。
这种方式在 Company 的 Code 字段是唯一的情况下非常有用特别是当你想要通过一个非主键的唯一标识符来建立模型之间的关联时。
Belongs to 的CRUD
点击关联模式链接获取belongs to相关的用法
预加载
这里刚刚已经说过了这里再补充 GORM允许通过使用Preload或者Joins来主动加载实体的关联关系。
外键约束
你可以通过OnUpdateOnDelete配置标签来增加关联关系的级联操作如下面的例子通过GORM可以完成用户和公司的级联更细和级联操作
type User struct {gorm.ModelName stringCompanyID intCompany Company gorm:constraint:OnUpdate:CASCADE,OnDelete:SET NULL;
}type Company struct {ID intName string
}
这段内容讲述了如何在 GORM 中**使用外键约束来定义关联关系中的级联操作。**在关系型数据库中级联操作是指当更新或删除一个表中的记录时自动对相关联的表中的记录执行特定的操作。这在管理具有外键关系的数据时非常有用因为它帮助维持数据库的引用完整性。 解析例子 例子中User 和 Company 之间存在一个关联关系其中 User 表通过 CompanyID 字段关联到 Company 表。
type User struct {gorm.ModelName stringCompanyID intCompany Company gorm:constraint:OnUpdate:CASCADE,OnDelete:SET NULL;
}type Company struct {ID intName string
}
OnUpdate:CASCADE这个配置表示如果 Company 表中的某条记录被更新例如其 ID 发生变化那么所有相关联的 User 记录的 CompanyID 字段也会相应地被更新。“CASCADE” 操作确保了数据的一致性即使在更新操作发生时。
OnDelete:SET NULL这个配置表示如果 Company 表中的某条记录被删除那么所有相关联的 User 记录中的 CompanyID 字段将被设置为 NULL。这样做的目的是在删除操作发生时避免产生悬浮引用即指向不存在的记录的外键同时也保留了 User 记录的其他信息。
为什么需要级联操作 级联操作的使用场景包括但不限于 数据一致性确保数据库中的数据保持一致性避免因为关联数据的变化而造成数据不一致的问题。 简化数据操作自动化处理关联数据的更新和删除操作减少手动编写额外逻辑的需要。
使用级联操作的注意事项 在使用级联删除OnDelete:CASCADE 时要特别小心因为它会导致删除一条记录时连带删除所有相关联的记录这可能不总是预期的行为。 确保数据库支持你要使用的级联操作。虽然大多数现代关系型数据库都支持这些操作但具体实现和支持的详细程度可能会有所不同。 在实现级联操作之前仔细考虑业务逻辑和数据完整性的需求以选择最适合的策略。
总结 通过在模型定义中使用 GORM 的 constraint 标签和相应的配置gorm:constraint:OnUpdate:CASCADE,OnDelete:SET NULL;你可以灵活地控制数据库外键约束的行为从而实现复杂的数据维护逻辑。
gorm Has One关系
Has One
has one与另一个模型建立一对一的关联但它和一对一关系又些许不同。这种关联表明一个模型的每个实例都包含或拥有另一个模型的一个实例。
例如你的应用包含user和credit card模型且每个user只能有一张credit card。
// User 有一张 CreditCardUserID 是外键
type User struct {gorm.ModelCreditCard CreditCard
}type CreditCard struct {gorm.ModelNumber stringUserID uint
}
解读 这段内容描述了在 GORM 中如何使用 “Has One” 关系来表示模型之间的一对一关联。这种关系表明一个模型在这个例子中是 User包含或拥有另一个模型CreditCard的单个实例。与 “Belongs To” 关系相比“Has One” 关系的方向性略有不同强调的是拥有关系即一个实体拥有另一个实体。
“Has One” 关系的特点 拥有方与被拥有方在 “Has One” 关系中通常有一个拥有方拥有另一个模型实例的模型和一个被拥有方被另一个模型实例拥有的模型。 外键的位置与 “Belongs To” 关系不同“Has One” 关系中的外键位于被拥有方在这个例子中是 CreditCard。 单一实例每个拥有方的实例最多只能拥有一个被拥有方的实例。
示例解析
type User struct {gorm.ModelCreditCard CreditCard // User 模型有一个 CreditCard 字段表示 User 拥有一张 CreditCard
}type CreditCard struct {gorm.ModelNumber string // CreditCard 的具体信息如卡号UserID uint // 外键指向 User 模型的 ID表示这张 CreditCard 属于哪个 User
}
User 模型代表用户它拥有一个 CreditCard 字段表示每个用户最多拥有一张信用卡。 CreditCard 模型代表信用卡包含一个 UserID 字段这是一个外键用于指向拥有该信用卡的用户。
数据库设计 在数据库层面CreditCard 表将包含一个 UserID 列存储与之关联的 User 记录的 ID 值。这表明每张信用卡都是由一个特定的用户拥有。
GORM 处理 当使用 GORM 自动迁移功能时GORM 会基于这些模型定义来创建相应的表并设置正确的外键约束。 当查询 User 时可以使用 GORM 的 Preload 功能来自动加载关联的 CreditCard从而一次性获取用户和他们的信用卡信息。
总结 “Has One” 关系在 GORM 中用于表示两个模型之间的一对一拥有关系其中外键位于被拥有方。这种关系允许模型清晰地表示它们之间的拥有关系同时通过外键约束维护数据库的引用完整性。
重写引用
默认情况下拥有者实体会将has one对于模型的主键保存为外键您也可以修改它用另外一个字段来保存例如下以恶个这个实验Name来保存的例子。 您可以实验标签references来更改它例如
type User struct {gorm.ModelName string gorm:indexCreditCard CreditCard gorm:foreignkey:UserName;references:name
}type CreditCard struct {gorm.ModelNumber stringUserName string
}
解读
这段内容解释了在 GORM 中如何自定义 “Has One” 关系中的外键和引用字段。在默认情况下“Has One” 关系通过将被拥有方例如 CreditCard的外键字段设置为引用拥有方例如 User的主键通常是 ID来建立。然而GORM 允许你通过使用 foreignkey 和 references 标签来自定义这些字段即指定一个非主键字段作为关联的依据。
示例解析 User 模型 拥有一个 CreditCard。不同于通常使用 User 的 ID 作为外键的做法这里使用 User 的 Name 字段作为外键的引用。 CreditCard 模型 包含一个 UserName 字段通过 gorm:“foreignkey:UserName;references:name” 标签指定这个字段作为外键它引用了 User 模型的 Name 字段。
外键与引用的自定义 foreignkey:UserName这部分告诉 GORMCreditCard 中的 UserName 字段应该用作外键。 references:name这部分指定 CreditCard 的外键 UserName 应该引用 User 模型中的 Name 字段而不是默认的 ID 字段。
引用解读我当时看到引用这个概念我觉得有点难懂 这里举一个具体的例子来进行解释这个概念 假设我们有两个表users 和 credit_cards。在常规的数据库设计中credit_cards 表可能通过 user_id 外键引用 users 表的主键 id 字段以建立两者之间的关系。但是在我们的特殊情况下我们希望通过 users 表的 name 字段来建立这种关系而不是通过 id 字段。
users 表
id name
1 Alice
2 Bobcredit_cards 表
id number user_name
1 1234-5678-9012 Alice
2 9876-5432-1098 Bob关系说明 每个 User 可以拥有一张 CreditCard。 CreditCard 表中的 user_name 字段用来存储与之关联的 User 的 name 值。
GORM 模型定义
type User struct {gorm.ModelName stringCreditCard CreditCard
}type CreditCard struct {gorm.ModelNumber stringUserName string gorm:index;
}
并且我们通过 gorm:“foreignkey:UserName;references:name” 在 User 模型中指定 CreditCard 的外键为 UserName 字段这个字段引用 User 模型中的 Name 字段。
实际数据库操作 当你在 GORM 中创建一个 User 并分配给他一张 CreditCard 时GORM 会把 CreditCard 的 UserName 字段设置为对应 User 的 Name 值。这意味着credit_cards 表中的 user_name 字段直接引用了 users 表的 name 字段的值而不是通常的主键 id 值。
重点 在这种设计中name 字段在 users 表中需要是唯一的因为它被用作连接两个表的参考值。 这种方法允许你根据业务逻辑或数据模型的特殊要求通过非主键字段建立表之间的关系。 使用 references 标签可以让你灵活地指定哪个字段应该被用作关系的参考这在处理复杂或非标准的数据库设计时非常有用。
多态关联
GORM为has one和has many提供了多态关联支持它会将拥有者实体的表名主键值都保存到多态类型的字段中。
type Cat struct {ID intName stringToy Toy gorm:polymorphic:Owner;
}type Dog struct {ID intName stringToy Toy gorm:polymorphic:Owner;
}type Toy struct {ID intName stringOwnerID intOwnerType 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)
解读 gorm:“polymorphic:Owner;” 标签详解 在 GORM 中使用 gorm:“polymorphic:Owner;” 标签是为了实现多态关系即允许一个模型如 Toy以通用的方式关联到多个其他模型如 Cat 和 Dog。
polymorphic这部分指明了这是一个多态关联。 Owner这里的 Owner 是一个标识符用于指示多态关联的名称。GORM 会使用这个名称来生成关联字段的名称。
多态关联的字段生成规则 当你在 Toy 结构体中声明 gorm:“polymorphic:Owner;” 时GORM 会自动基于 Owner 这个标识符生成两个字段 OwnerID这个字段用来存储拥有者的主键值。在这个例子中如果 Toy 是属于 Dog则 OwnerID 会存储那只 Dog 的 ID 值。 OwnerType这个字段用来标识拥有者的类型。在多个不同的模型中使用相同的多态关联时OwnerType 用于区分这个 Toy 属于哪一个模型例如 “dogs” 或 “cats”。
多态关联是一个非常强大的数据库模型设计概念它允许一个模型在这个例子中是 Toy关联到多个其他模型如 Cat 和 Dog而不需要为每个关联创建单独的外键列。在 GORM 中这通过在 Toy 模型中使用两个字段 OwnerID 和 OwnerType 来实现这两个字段共同定义了 Toy 的拥有者。
多态关联的工作原理 OwnerID 字段 存储了拥有者记录的主键值即 Cat 或 Dog 表中某条记录的 ID。 OwnerType 字段 存储了拥有者的类型用于区分 Toy 是属于 Cat 还是 Dog。 这通常是拥有者表名的字符串表示。
示例解析 根据提供的例子当你创建一个 Dog 实例并给它分配一个 Toy 时GORM 会自动填充 Toy 表的 OwnerID 和 OwnerType 字段以表明这个 Toy 属于哪个 Dog 实例。
db.Create(Dog{Name: dog1, Toy: Toy{Name: toy1}})
这个操作会生成以下 SQL 语句 1.首先插入 Dog 记录到 dogs 表。
INSERT INTO dogs (name) VALUES (dog1)
2.然后插入 Toy 记录到 toys 表同时设置 owner_id 为新插入的 Dog 记录的 IDowner_type 设置为 “dogs” 来表明这个 Toy 属于 Dog 表的记录。
INSERT INTO toys (name,owner_id,owner_type) VALUES (toy1, 1, dogs)
多态关联的优势 灵活性多态关联提供了极大的灵活性允许一个模型实例关联到多个不同类型的模型实例上而不需要为每种类型的关联创建单独的字段或表。 简化模型设计通过减少需要的外键和表多态关联可以简化数据库模型的设计使其更加干净、简洁。
使用场景 多态关联特别适合那些需要将一个模型如 Toy与多个其他模型如 Cat、Dog 等进行灵活关联的情况。这种设计模式在实现如评论系统、收藏功能、图片上传等功能时特别有用其中一个项如评论、收藏、图片可以属于应用中的多个不同模型如文章、产品、用户等。
总结 考虑到上面的例子通过在 Toy 结构体中使用 gorm:“polymorphic:Owner;” 标签GORM 知道如何处理 Toy 和其他模型Cat、Dog之间的多态关系。这意味着在数据库操作时GORM 会自动设置 OwnerID 和 OwnerType 字段以正确地反映每个 Toy 所属的实体。
您也可以实验标签polymorphicValue来更改多态类型的值例如
type Dog struct {ID intName stringToy Toy gorm:polymorphic:Owner;polymorphicValue:master
}type Toy struct {ID intName stringOwnerID intOwnerType 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)
解读 这段Go代码展示了如何在使用GORM一个Go语言的ORM库时实现多态关联。多态关联是指一个模型可以属于多个其他模型中的任意一个。在这个例子中Dog 和 Toy 模型通过多态方式相关联这意味着一个玩具可以属于不同类型的拥有者在这个例子中是 Dog而不是仅限于一个特定的模型。
1.Dog 结构体代表狗每只狗都有一个ID、一个名字以及一个玩具Toy。在 Toy 结构体中通过标签 gorm:“polymorphic:Owner;polymorphicValue:master” 指定了多态关联。这里Owner 是多态字段的前缀。
2.Toy 结构体代表玩具每个玩具有自己的ID、名字、拥有者ID (OwnerID)和拥有者类型 (OwnerType)。OwnerID 和 OwnerType 字段共同决定了玩具的拥有者。
3.在这个多态关联中polymorphic:Owner 告诉GORM这是一个多态关联Owner 是多态类型和ID字段的前缀。polymorphicValue:master 指定了当当前模型在这个例子中是 Dog作为拥有者时OwnerType 字段的值应该是什么。 在这个例子中无论何时创建一个 Dog 实例并给它分配一个玩具OwnerType 都会被设置为 “master”。
4.当调用 db.Create(Dog{Name: “dog1”, Toy: Toy{Name: “toy1”}}) 时GORM 会先插入一个 Dog 记录然后插入一个 Toy 记录。在插入 Toy 记录时它会自动将 OwnerID 设置为刚刚插入的 Dog 记录的ID并将 OwnerType 设置为 “master”。
总结这段代码通过GORM的多态关联功能演示了如何灵活地将 Toy 模型关联到 Dog 模型同时允许 Toy 模型可能在未来关联到其他类型的模型上通过指定 polymorphicValue 来明确指出拥有者类型。这种方式在数据库设计中非常有用因为它提供了很高的灵活性和可扩展性。
预加载
GORM可以通过Preload、joins预加载has one关联的记录。
自引用Has One
type User struct {gorm.ModelName stringManagerID *uintManager *User
}
解读 这段Go代码展示了使用GORM库在Go中实现自引用关系的例子。在这个例子中我们定义了一个 User 结构体用来表示用户。这里使用的自引用关系是一种特殊的关联关系它允许一个实体在这个场景下是 User引用另一个相同类型的实体。 这种模式在需要表示层级或树形结构的数据时非常有用比如组织架构中的经理与下属关系。
具体来看 User 结构体的定义 **gorm.Model**这是GORM提供的一个基础模型它自动包含了几个常见的字段如 ID, CreatedAt, UpdatedAt, DeletedAt。使用它可以方便地为你的模型添加这些通用字段。
Name: 表示用户的名字是一个字符串类型的字段。
ManagerID: 是一个指向 uint无符号整型的指针用来存储管理该用户的经理的ID。这个字段是可选的因为它是一个指针在Go中指针可以为 nil表示没有值。这样设计允许某些用户没有直接的经理例如公司的CEO可能没有经理。
Manager: 是一个指向 User 类型的指针表示这个用户的经理。 这个字段通过 ManagerID 与同一张表中的另一个 User 记录相关联。它实现了自引用关系**即一个用户下属引用另一个用户经理作为它的经理。**
这种自引用结构允许你构建一种层次结构例如公司的员工和管理层级。你可以通过 ManagerID 字段来设置某个用户的经理然后通过 Manager 字段来访问这个经理的详细信息。例如如果你想找到某个用户的经理的名字你可以通过这个用户的 Manager 字段来访问。
外键约束
你可以通过constraint配置OnUpdate、OnDelete实现外键约束在使用GORM进行迁移时就会被创建例如
type User struct {gorm.ModelCreditCard CreditCard gorm:constraint:OnUpdate:CASCADE,OnDelete:SET NULL;
}type CreditCard struct {gorm.ModelNumber stringUserID uint
}
这个例子我认为很直观了。