GORM の基本 -- 関連付け

1、所属

Belongs to ( belongs to) 関連付けは、宣言されたモデルの各インスタンスが他のモデルのインスタンスに「属する」ように、別のモデルとの 1 対 1 の接続を設定します。

たとえば、アプリケーションにユーザー (ユーザー) と会社 (会社) が含まれており、各ユーザーを 1 つの会社にしか割り当てることができない場合、次のタイプはこの関係を表します。ここで、UserオブジェクトにはCompanyIDと があることに注意してくださいCompanyデフォルトでは、CompanyIDはテーブル間の外部キー リレーションシップを作成するために暗黙的に使用されるため、内部構造を設定するために構造体UserCompany含める必要があります。UserCompany

// `User` belongs to `Company`, `CompanyID` is the foreign key
type User struct {
    
    
  gorm.Model
  Name      string
  CompanyID int
  Company   Company
}

type Company struct {
    
    
  ID   int
  Name string
}

内部の設定の詳細については、 Eager Loadingを参照してください

1.1 外部キーのオーバーライド

属している関係を定義するには、外部キーが存在する必要があります。デフォルトの外部キーは、所有者 (所有者) のタイプ名とそのプライマリ フィールド名を使用します。

上記の例では、モデルが属するモデルを定義するにはCompanyUser慣例により、外部キーは次のようになります。CompanyID

GORM は、外部キーをカスタマイズする方法を提供します。次に例を示します。

type User struct {
    
    
  gorm.Model
  Name         string
  CompanyRefer int
  Company      Company `gorm:"foreignKey:CompanyRefer"`
  // use CompanyRefer as foreign key
}

type Company struct {
    
    
  ID   int
  Name string
}

1.2 参照のオーバーライド

所属関係の場合、GORM通常、所有者の主キー フィールドを外部キーの値として使用しますCompanyID

ユーザーを会社に割り当てると、GORM はID会社をユーザーのフィールドに保存しますCompanyID次のように、ラベルごとに変更
できます。references

type User struct {
    
    
  gorm.Model
  Name      string
  CompanyID string
  Company   Company `gorm:"references:Code"` // use Code as references
}

type Company struct {
    
    
  ID   int
  Code string
  Name string
}

GORM は通常、リレーションが であると推測しますhas one。オーバーライド外部キー名が所有者型に既に存在する場合は、belongs to リレーションで指定する必要がありますreferences

type User struct {
    
    
  gorm.Model
  Name      string
  CompanyID string
  Company   Company `gorm:"references:CompanyID"` // use Company.CompanyID as references
}

type Company struct {
    
    
  CompanyID   int
  Code        string
  Name        string
}

1.3 属している CRUD

使用するbelongs to関係の関連付けモード(Association Mode )

1.4 イーガーローディング

GORM では、 EagerLoading 属性の関連Preload 付けを使用できます詳細については、EagerLoading (Just-In-Time Loading) を参照してください。Joinsbelongs to

1.5 外部キー制約

タグを使用して制約constraintを設定すると、移行で作成されます。次に例を示します。OnUpdateOnDeleteGORM

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
}

2、ある

has one関連付け。別のモデルと 1 対 1 で接続しますが、セマンティクス (および結果) がわずかに異なります。この関連付けは、あるモデルの各インスタンスが別のモデルのインスタンスを含むか所有していることを示します。
たとえば、アプリケーションにユーザーとクレジット カードが含まれていて、各ユーザーが持つことができるクレジット カードは 1 つだけであるとします。

2.1 ステートメント

// User has one CreditCard, UserID is the foreign key
type User struct {
    
    
  gorm.Model
  CreditCard CreditCard
}

type CreditCard struct {
    
    
  gorm.Model
  Number string
  UserID uint
}

2.2 検索

// Retrieve user list with eager loading credit card
func GetAll(db *gorm.DB) ([]User, error) {
    
    
  var users []User
  err := db.Model(&User{
    
    }).Preload("CreditCard").Find(&users).Error
  return users, err
}

2.3 外部キーのオーバーライド

リレーションシップの場合has one、外部キー フィールドも存在する必要があり、所有者はそれに属するモデルの主キーをこのフィールドに保持します。

フィールドの名前は通常、has oneモデルのタイプとその主キー (上記の例では )から生成されますUserID

ユーザーにクレジットカードを提供すると、IDユーザーがUserIDフィールドに保存されます。

リレーションシップを保持するために別のフィールドを使用する場合は、foreignKeyタグを使用して変更できます。次に例を示します。

type User struct {
    
    
  gorm.Model
  CreditCard CreditCard `gorm:"foreignKey:UserName"`
  // use UserName as foreign key
}

type CreditCard struct {
    
    
  gorm.Model
  Number   string
  UserName string
}

2.4 カバーリファレンス

デフォルトでは、所有エンティティは所有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
}

2.5 ポリモルフィック アソシエーション

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")

2.6 Has One を使用した CRUD

関連モデル参照してください。has one

2.7 プリロード

GORM では、アソシエーションPreload のプリロードが可能です詳細については、プリロード (オンザフライ ロード)を参照してください。Joinshas one

自己参照には 1 つある

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

2.8 外部キー制約

GORMの移行時に作成されるタグを使用して制約をconstraint設定できます。たとえば、次のようになります。OnUpdateOnDelete

type User struct {
    
    
  gorm.Model
  CreditCard CreditCard `gorm:"constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
}

type CreditCard struct {
    
    
  gorm.Model
  Number string
  UserID uint
}

選択して削除の詳細を使用して、選択しSelect has one 関連付けを削除することもできます

3、たくさんある

3.1 たくさんある

has many関連付け、別のモデルとの1 対多 ( 1 対多has one) の接続を確立します。所有モデルとは異なり、所有者は 0 個以上のモデル インスタンスを持つことができます。

たとえば、アプリケーションにユーザーとクレジット カードが含まれており、各ユーザーが多数のクレジット カードを持つことができる場合です。

3.2 宣言する

// User has many CreditCards, UserID is the foreign key
type User struct {
    
    
  gorm.Model
  CreditCards []CreditCard
}

type CreditCard struct {
    
    
  gorm.Model
  Number string
  UserID uint
}

3.3 検索

// Retrieve user list with eager loading credit cards
func GetAll(db *gorm.DB) ([]User, error) {
    
    
    var users []User
    err := db.Model(&User{
    
    }).Preload("CreditCards").Find(&users).Error
    return users, err
}

3.4 外部キーのオーバーライド

リレーションシップを定義するにはhas many、外部キーが存在する必要があります。デフォルトの外部キーの名前は、所有者の型名とその主キー フィールドの名前です。

たとえば、Userに属するモデルを定義するには、外部キーは である必要がありますUserID

他のフィールドを外部キーとして使用して、ラベルをカスタマイズできますforeignKey。次に例を示します。

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

type CreditCard struct {
    
    
  gorm.Model
  Number    string
  UserRefer uint
}

3.5 参照のオーバーライド

GORM は通常、所有者の主キーを外部キーの値として使用します。上記の例でUserID

ユーザーにクレジット カードを割り当てると、GORM はユーザーの情報をクレジット カードのフィールドにID保存します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
}

3.6 ポリモーフィック関連

GORM は多態的な関連付けをサポートし、エンティティのテーブル名を多態的な型 (type) のフィールドに保存し、主キーの値を多態的なフィールドに保存します

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")

3.7 Has Many を使用した CRUD

関連モデル参照してください。has many

3.8 プリロード

GORM では、プリロードを使用してアソシエーションをプリロードできますPreloadhas many詳細については、プリロード (高速ロード)を参照してください。

自己参照には多くの

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

3.9 外部キー制約

タグの有無にかかわらず制約constraintを設定できます。これは、GORM の移行時に作成されます。次に例を示します。OnUpdateOnDelete

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 関連付けを削除することもできます

4、多対多

多対多では、2 つのモデル間に結合テーブルが追加されます。

たとえば、アプリケーションにユーザーと言語が含まれている場合、1 人のユーザーが複数の言語を話すことができ、多くのユーザーが指定された言語を話すことができます。

// User has and belongs to many languages, `user_languages` is the join table
type User struct {
    
    
  gorm.Model
  Languages []Language `gorm:"many2many:user_languages;"`
}

type Language struct {
    
    
  gorm.Model
  Name string
}

GORM を使用してテーブルを作成すると、AutoMigrateGORM自動的に結合テーブルを作成します。User

4.1 後方参照

宣言する

// User has and belongs to many languages, use `user_languages` as join table
type User struct {
    
    
  gorm.Model
  Languages []*Language `gorm:"many2many:user_languages;"`
}

type Language struct {
    
    
  gorm.Model
  Name string
  Users []*User `gorm:"many2many:user_languages;"`
}

取得する

// Retrieve user list with eager loading languages
func GetAllUsers(db *gorm.DB) ([]User, error) {
    
    
  var users []User
  err := db.Model(&User{
    
    }).Preload("Languages").Find(&users).Error
  return users, err
}

// Retrieve language list with eager loading users
func GetAllLanguages(db *gorm.DB) ([]Language, error) {
    
    
  var languages []Language
  err := db.Model(&Language{
    
    }).Preload("Users").Find(&languages).Error
  return languages, err
}

4.2 外部キーのオーバーライド

多対多の関係の場合、結合テーブルには 2 つのモデルを参照する外部キーがあります。次に例を示します。

type User struct {
    
    
  gorm.Model
  Languages []Language `gorm:"many2many:user_languages;"`
}

type Language struct {
    
    
  gorm.Model
  Name string
}

// Join Table: user_languages
//   foreign key: user_id, reference: users.id
//   foreign key: language_id, reference: languages.id

それらをオーバーライドするにはforeignKey、タグreferences、、、、を使用できます。それらを一緒に使用する必要はありません。そのうちの 1 つを使用して、いくつかの外部キー/参照をオーバーライドできます。joinForeignKeyjoinReferences

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"`
}

// Which creates join table: user_profiles
//   foreign key: user_refer_id, reference: users.refer
//   foreign key: profile_refer, reference: profiles.user_refer

注:一部のデータベースでは、一意のインデックスを持つフィールドを参照するデータベース外部キーの作成のみが許可されているため、移行時にデータベース外部キーを作成する場合は、フラグ
を指定する必要がありますunique index

4.3 自己参照型 Many2Many

type User struct {
    
    
  gorm.Model
  Friends []*User `gorm:"many2many:user_friends"`
}

// Which creates join table: user_friends
//   foreign key: user_id, reference: users.id
//   foreign key: friend_id, reference: users.id

4.4 イーガーローディング

GORM では、プリロードを使用してアソシエーションをプリロードできますPreloadmany2many 詳細については、プリロード (高速ロード)を参照してください。

4.5 Many2Many での CRUD

関連モデル参照してください。has many

4.6 カスタム結合テーブル

JoinTableSoft Deleteたとえば、soft delete( )、hook( Hooks ) のサポートと、それを設定するSetupJoinTableために使用できるなど、完全に機能するモデルにすることができます。

注:
カスタム接続テーブルの外部キーは、複合主キーまたは複合一意インデックスである必要があります

type Person struct {
    
    
  ID        int
  Name      string
  Addresses []Address `gorm:"many2many:person_address;"`
}

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 {
    
    
  // ...
}

// Change model Person's field Addresses' join table to PersonAddress
// PersonAddress must defined all required foreign keys or it will raise error
err := db.SetupJoinTable(&Person{
    
    }, "Addresses", &PersonAddress{
    
    })

4.7 外部キー制約

GORMの移行時に作成されるタグ使用して制約constraintを設定できます。たとえば、次のようになります。OnUpdateOnDelete

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 関連付けを削除することもできます

4.8 複合外部キー

モデルが複合主キーを使用している場合、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"`
}

// Join Table: 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

// Join Table: locale_blog_tags
//   foreign key: blog_id, reference: blogs.id
//   foreign key: blog_locale, reference: blogs.locale
//   foreign key: tag_id, reference: tags.id

// Join Table: shared_blog_tags
//   foreign key: blog_id, reference: blogs.id
//   foreign key: tag_id, reference: tags.id

5. アソシエーション モデル

5.1 自動作成・更新

GORM は、レコードの作成/更新時にUpsert自動保存関連付けとその参照を使用します。

user := User{
    
    
  Name:            "jinzhu",
  BillingAddress:  Address{
    
    Address1: "Billing Address - Address 1"},
  ShippingAddress: Address{
    
    Address1: "Shipping Address - Address 1"},
  Emails:          []Email{
    
    
    {
    
    Email: "[email protected]"},
    {
    
    Email: "[email protected]"},
  },
  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, "[email protected]"), (111, "[email protected]") 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, "[email protected]"), (111, "[email protected]") ON DUPLICATE KEY SET email=VALUES(email);
// ...

5.2 自動作成・更新をスキップする

Select作成/更新時に自動保存をスキップするには、または を使用できますOmit。次に例を示します。

user := User{
    
    
  Name:            "jinzhu",
  BillingAddress:  Address{
    
    Address1: "Billing Address - Address 1"},
  ShippingAddress: Address{
    
    Address1: "Shipping Address - Address 1"},
  Emails:          []Email{
    
    
    {
    
    Email: "[email protected]"},
    {
    
    Email: "[email protected]"},
  },
  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

注:関連付け
の場合、 GORM は結合テーブル参照を作成する前に関連付けを挿入します。関連付けの挿入をスキップしたい場合は、次のようにスキップできます。many2many

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

以下のコードは、関連付けとその参照の作成をスキップします

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

5.3Select/Omit関連フィールドの選択/省略 ( )

user := User{
    
    
  Name:            "jinzhu",
  BillingAddress:  Address{
    
    Address1: "Billing Address - Address 1", Address2: "addr2"},
  ShippingAddress: Address{
    
    Address1: "Shipping Address - Address 1", Address2: "addr2"},
}

// Create user and his BillingAddress, ShippingAddress
// When creating the BillingAddress only use its address1, address2 fields and omit others
db.Select("BillingAddress.Address1", "BillingAddress.Address2").Create(&user)

db.Omit("BillingAddress.Address2", "BillingAddress.CreatedAt").Create(&user)

5.4 アソシエーションモード

Association パターンには、リレーションシップを処理するための一般的なヘルパー メソッドが含まれています。

// Start Association Mode
var user User
db.Model(&user).Association("Languages")
// `user` is the source model, it must contains primary key
// `Languages` is a relationship's field name
// If the above two requirements matched, the AssociationMode should be started successfully, or it should return error
db.Model(&user).Association("Languages").Error

5.4.1 関連付けの検索

マッチング協会

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)

5.4.2 アペンド・アソシエーション

の場合many to manyhas many新しい関連付けを追加し、 の場合has onebelongs 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"})

5.4.3 関連付けの置換

現在の関連付けを新しいものに置き換えます

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

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

5.4.4 関連付けの削除

ソースとパラメーターの間の関係が存在する場合は削除します。参照のみが削除され、これらのオブジェクトは DB から削除されません。

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

5.4.5 関連付けのクリア

ソースと関連付けの間のすべての参照を削除しますが、これらの関連付けは削除しません

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

5.4.6 カウント関連付け

現在の関連付けの数を返します

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

// Count with conditions
codes := []string{
    
    "zh-CN", "en-US", "ja-JP"}
db.Model(&user).Where("code IN ?", codes).Association("Languages").Count()

5.4.7 バッチデータ

アソシエーション モードは、次のようなバルク データをサポートします。

// Find all roles for all users
db.Model(&users).Association("Role").Find(&roles)

// Delete User A from all user's team
db.Model(&users).Association("Team").Delete(&userA)

// Get distinct count of all users' teams
db.Model(&users).Association("Team").Count()

// For `Append`, `Replace` with batch data, the length of the arguments needs to be equal to the data's length or else it will return an error
var users = []User{
    
    user1, user2, user3}
// e.g: we have 3 users, Append userA to user1's team, append userB to user2's team, append userA, userB and userC to user3's team
db.Model(&users).Association("Team").Append(&userA, &userB, &[]User{
    
    userA, userB, userC})
// Reset user1's team to userA,reset user2's team to userB, reset user3's team to userA, userB and userC
db.Model(&users).Association("Team").Replace(&userA, &userB, &[]User{
    
    userA, userB, userC})

5.5 選択による削除

Select レコードを削除するときは、 [選択した関係の削除]を使用できますhas one/has many/many2many例えば:

// delete user's account when deleting user
db.Select("Account").Delete(&user)

// delete user's Orders, CreditCards relations when deleting user
db.Select("Orders", "CreditCards").Delete(&user)

// delete user's has one/many/many2many relations when deleting user
db.Select(clause.Associations).Delete(&user)

// delete each user's account when deleting users
db.Select("Account").Delete(&users)

注:
アソシエーションは、削除されたレコードにゼロ以外の主キーがある場合にのみ削除されます。GORM は、これらの主キーを選択したアソシエーションを削除する基準として使用します。

// DOESN'T WORK
db.Select("Account").Where("name = ?", "jinzhu").Delete(&User{
    
    })
// will delete all user with name `jinzhu`, but those user's account won't be deleted

db.Select("Account").Where("name = ?", "jinzhu").Delete(&User{
    
    ID: 1})
// will delete the user with name = `jinzhu` and id = `1`, and user `1`'s account will be deleted

db.Select("Account").Delete(&User{
    
    ID: 1})
// will delete the user with id = `1`, and user `1`'s account will be deleted

5.6 関連タグ

鬼ごっこ 説明
外部キー 結合テーブルへの外部キーとして使用される現在のモデルの列名を指定します
参考文献 結合テーブルの外部キーにマップされる参照のテーブルの列名を指定します
多形的な モデル名などの多態型を指定
polymorphicValue ポリモーフィック値、デフォルトのテーブル名を指定
たくさん 結合テーブル名を指定
joinForeignKey 現在のテーブルにマップする結合テーブルの外部キー列名を指定します
結合参照 参照のテーブルにマップする結合テーブルの外部キー列名を指定します
制約 関係制約、例: OnUpdate、OnDelete

6、プリロード(イーガーロード)

6.1 プリロード

GORM をPreload使用すると、高速読み込みの関連付けを他の SQL で使用できます。次に例を示します。

type User struct {
    
    
  gorm.Model
  Username string
  Orders   []Order
}

type Order struct {
    
    
  gorm.Model
  UserID uint
  Price  float64
}

// Preload Orders when find users
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

6.2 ジョインのプリロード

Preload単一のクエリで関連データを読み込むと、Join Preload内部結合を使用して関連データが読み込まれます。次に例を示します。

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})

条件付きで参加

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 Preload1 対 1 の関係で動作します。例: has onebelong to

6.3 すべてプリロード

作成/更新の場合、同様の で使用できclause.Associationsます。たとえば、次のようにすべての関連付けに使用できます。Preload Select 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)

6.4 条件付きプリロード

GORM では、関連付けの条件付きプリロードが可能で、インライン条件付きのように機能します

// Preload Orders with conditions
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');

6.5 カスタムのプリロード SQL

を渡すことで、プリロード SQL をカスタマイズできますfunc(db *gorm.DB) *gorm.DB。次に例を示します。

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;

6.6 ネストされたプリロード

GORM はネストされたプリロードをサポートします。次に例を示します。

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

// Customize Preload conditions for `Orders`
// And GORM won't preload unmatched order's OrderItems then
db.Preload("Orders", "state = ?", "paid").Preload("Orders.OrderItems").Find(&users)

おすすめ

転載: blog.csdn.net/chinusyan/article/details/129655109