GEN 會自動儲存關聯,就像 GORM 所做的那樣。關聯(BelongsTo/HasOne/HasMany/Many2Many)會重複使用 GORM 的標籤。 目前此功能只支援現有的模型。
關聯
有 4 種關聯。
const ( HasOne RelationshipType = RelationshipType(schema.HasOne) // HasOneRel has one relationship HasMany RelationshipType = RelationshipType(schema.HasMany) // HasManyRel has many relationships BelongsTo RelationshipType = RelationshipType(schema.BelongsTo) // BelongsToRel belongs to relationship Many2Many RelationshipType = RelationshipType(schema.Many2Many) // Many2ManyRel many to many relationship )
與現有模型關聯
package model
// exist model type Customer struct { gorm.Model CreditCards []CreditCard `gorm:"foreignKey:CustomerRefer"` }
type CreditCard struct { gorm.Model Number string CustomerRefer uint }
GEN 會偵測模型的關聯
// specify model g.ApplyBasic(model.Customer{}, model.CreditCard{})
// assoications will be detected and converted to code package query
type customer struct { ... CreditCards customerHasManyCreditCards }
JSONTag string// related field's JSON tag GORMTag string// related field's GORM tag NewTag string// related field's new tag OverwriteTag string// related field's tag }
// delete user's account when deleting user u.Select(u.Account).Delete(&user)
// delete user's Orders, CreditCards relations when deleting user db.Select(u.Orders.Field(), u.CreditCards.Field()).Delete(&user)
// delete user's has one/many/many2many relations when deleting user db.Select(field.AssociationFields).Delete(&user)
預載入
目前此功能只支援現有的模型。
預載入
GEN 允許在其他 SQL 中使用 Preload 急切載入關係,例如
type User struct { gorm.Model Username string Orders []Order }
type Order struct { gorm.Model UserID uint Price float64 }
q := query.Use(db) u := q.User o := q.Order
// Preload Orders when find users users, err := u.WithContext(ctx).Preload(u.Orders).Find() // SELECT * FROM users; // SELECT * FROM orders WHERE user_id IN (1,2,3,4);
users, err := u.WithContext(ctx).Preload(u.Orders).Preload(u.Profile).Preload(u.Role).Find() // 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
type User struct { gorm.Model CreditCards []CreditCard `gorm:"foreignKey:UserRefer"` }
type CreditCard struct { gorm.Model Number string UserRefer uint }
u := q.User cc := q.CreditCard
// !!! Foregin key "cc.UserRefer" must be selected users, err := u.WithContext(ctx).Where(c.ID.Eq(1)).Preload(u.CreditCards.Select(cc.Number, cc.UserRefer)).Find() // SELECT * FROM `credit_cards` WHERE `credit_cards`.`customer_refer` = 1 AND `credit_cards`.`deleted_at` IS NULL // SELECT * FROM `customers` WHERE `customers`.`id` = 1 AND `customers`.`deleted_at` IS NULL LIMIT 1
使用條件預載入
GEN 允許使用條件預載入關聯,其運作方式類似於內嵌條件。
q := query.Use(db) u := q.User o := q.Order
// Preload Orders with conditions users, err := u.WithContext(ctx).Preload(u.Orders.On(o.State.NotIn("cancelled")).Find() // SELECT * FROM users; // SELECT * FROM orders WHERE user_id IN (1,2,3,4) AND state NOT IN ('cancelled');
users, err := u.WithContext(ctx).Where(u.State.Eq("active")).Preload(u.Orders.On(o.State.NotIn("cancelled")).Find() // SELECT * FROM users WHERE state = 'active'; // SELECT * FROM orders WHERE user_id IN (1,2) AND state NOT IN ('cancelled');
users, err := u.WithContext(ctx).Preload(u.Orders.Order(o.ID.Desc(), o.CreateTime).Find() // SELECT * FROM users; // SELECT * FROM orders WHERE user_id IN (1,2) Order By id DESC, create_time;
users, err := u.WithContext(ctx).Preload(u.Orders.On(o.State.Eq("on")).Order(o.ID.Desc()).Find() // SELECT * FROM users; // SELECT * FROM orders WHERE user_id IN (1,2) AND state = "on" Order By id DESC;
users, err := u.WithContext(ctx).Preload(u.Orders.Clauses(hints.UseIndex("idx_order_id"))).Find() // SELECT * FROM users; // SELECT * FROM orders WHERE user_id IN (1,2) USE INDEX (`idx_order_id`);
user, err := u.WithContext(ctx).Where(u.ID.Eq(1)).Preload(u.Orders.Offset(100).Limit(20)).Take() // SELECT * FROM users WHERE `user_id` = 1 LIMIT 20 OFFSET 100; // SELECT * FROM `users` WHERE `users`.`id` = 1 LIMIT 1
// Customize Preload conditions for `Orders` // And GEN won't preload unmatched order's OrderItems then db.Preload(u.Orders.On(o.State.Eq("paid"))).Preload(u.Orders.OrderItems).Find(&users)