Skip to content
On this page

关联之多对多

一个女神可以有多个狗哥,一个狗哥也可以有多个女神

Go
type M2MWallet struct {
	ID       uint
	Amount   float64
	M2MDogID uint // 外键,就是M2MDog.ID
}

type M2MDog struct {
	ID          uint
	Name        string
	M2MGirlGods []M2MGirlGod `gorm:"many2many:dog_girl_god"` // 一个狗哥可以关联多个女神
	M2MWallet   M2MWallet
}

type M2MGirlGod struct {
	ID      uint
	Name    string
	M2MDogs []M2MDog `gorm:"many2many:dog_girl_god"` // 一个女神可以关联多个狗哥
}

自动迁移

Go
func autoMigrate() {
	DB.AutoMigrate(&M2MDog{}, &M2MGirlGod{}, &M2MWallet{})
}

执行上面代码会创建4个表,除了上面声明的3个表,会额外创建dog_girl_god表(通过声明的gorm:"many2many:dog_girl_god"tag自动生成的),该表记录了M2MDogM2MGirlGod之间的关联关系

SQL
CREATE TABLE dog_girl_god
(
    m2_m_girl_god_id bigint UNSIGNED NOT NULL,
    m2_m_dog_id      bigint UNSIGNED NOT NULL,
    PRIMARY KEY (m2_m_girl_god_id, m2_m_dog_id),
    CONSTRAINT fk_dog_girl_god_m2_m_dog
        FOREIGN KEY (m2_m_dog_id) REFERENCES m2_m_dogs (id),
    CONSTRAINT fk_dog_girl_god_m2_m_girl_god
        FOREIGN KEY (m2_m_girl_god_id) REFERENCES m2_m_girl_gods (id)
);

准备数据

Go
// 创建几个狗哥
func createM2MData() {
	d1 := M2MDog{Name: "狗哥1号"}
	d2 := M2MDog{Name: "狗哥2号"}
	d3 := M2MDog{Name: "狗哥3号"}
	d4 := M2MDog{Name: "狗哥4号"}
	d5 := M2MDog{Name: "狗哥5号"}
	d6 := M2MDog{Name: "狗哥6号"}
	dogs := []M2MDog{d1, d2, d3, d4, d5, d6}
	DB.Model(&M2MDog{}).Create(&dogs)
}
// 创建女神并关联狗哥
func girl2DogAssociation() {
	// 狗哥1号
	var d1 M2MDog
	DB.Model(&M2MDog{}).Find(&d1, 1)
	// 创建女神1号 并将其和狗哥1号关联
	//g1 := M2MGirlGod{Name: "女神1号"}
	//DB.Model(&d1).Association("M2MGirlGods").Append(&g1)
	// 创建女神2号 并将其和狗哥1号关联
	//g2 := M2MGirlGod{Name: "女神2号"}
	//DB.Model(&d1).Association("M2MGirlGods").Append(&g2)
	// 创建女神3、4号 并将其和狗哥1号关联
	g3 := M2MGirlGod{Name: "女神3号"}
	g4 := M2MGirlGod{Name: "女神4号"}
	DB.Model(&d1).Association("M2MGirlGods").Append(&g3, &g4)
}

准备M2MWallet数据

json
[
  {
    "id": 1,
    "amount": 10000,
    "m2_m_dog_id": 1
  },
  {
    "id": 2,
    "amount": 80000,
    "m2_m_dog_id": 2
  },
  {
    "id": 3,
    "amount": 6000,
    "m2_m_dog_id": 3
  }
]

修改dog_girl_god

狗哥1号关联了女神1、2、3、4

女神一号关联了狗哥1、2、3

json
[
  {
    "m2_m_girl_god_id": 1,
    "m2_m_dog_id": 1
  },
  {
    "m2_m_girl_god_id": 2,
    "m2_m_dog_id": 1
  },
  {
    "m2_m_girl_god_id": 3,
    "m2_m_dog_id": 1
  },
  {
    "m2_m_girl_god_id": 4,
    "m2_m_dog_id": 1
  },
  {
    "m2_m_girl_god_id": 1,
    "m2_m_dog_id": 2
  },
  {
    "m2_m_girl_god_id": 1,
    "m2_m_dog_id": 3
  }
]

增删改

和之前的一对一一对多的差不多

查询

查询女神1号关联的狗哥的数据,带上狗哥的小金库信息

Go
func queryGirl() {
	// 查出女神1号
	var g1 M2MGirlGod
	DB.Model(&M2MGirlGod{}).Find(&g1, 1)
	var dogs []M2MDog
	// 查询女神1号关联的狗哥
	DB.Model(&g1).Preload("M2MWallet").Association("M2MDogs").Find(&dogs)
	// 女神1号关联的狗哥 => [{1 狗哥1号 [] {1 10000 1}} {2 狗哥2号 [] {2 80000 2}} {3 狗哥3号 [] {3 6000 3}}]
	fmt.Printf("女神1号关联的狗哥 => %v\n", dogs)
}

查询女神1号关联的狗哥的数据,带上狗哥的小金库信息,并带出狗哥的女神的信息

Go
func queryGirl() {
	// 查出女神1号
	var g1 M2MGirlGod
	DB.Model(&M2MGirlGod{}).Find(&g1, 1)
	var dogs []M2MDog
	// 查询女神1号关联的狗哥
	//DB.Model(&g1).Preload("M2MWallet").Association("M2MDogs").Find(&dogs)
	DB.Model(&g1).Preload("M2MWallet").Preload("M2MGirlGods").Association("M2MDogs").Find(&dogs)
	/**
	女神1号关联的狗哥 => [{1 狗哥1号 [{1 女神1号 []} {2 女神2号 []} {3 女神3号 []} {4 女神4号 []}] {1 10000 1}} {2 狗哥2号 [{1 女神1号 []}] {2 80000 2}} {3 狗哥3号 [{1 女神1号 []}]
	*/
	fmt.Printf("女神1号关联的狗哥 => %v\n", dogs)
}

查询女神1号关联的狗哥的数据,带上狗哥的小金库信息,并且要余额大于等于10000

Go
func queryByJoin() {
	// 查出女神1号
	var g1 M2MGirlGod
	DB.Model(&M2MGirlGod{}).Find(&g1, 1)
	var dogs []M2MDog
	DB.Model(&M2MDog{})
	    .Preload("M2MWallet")
	    .Joins("JOIN dog_girl_god dg ON dg.m2_m_dog_id = m2_m_dogs.id")
	    .Joins("JOIN m2_m_wallets w on w.m2_m_dog_id = m2_m_dogs.id")
	    .Where("dg.m2_m_girl_god_id = ?", g1.ID)
	    .Where("w.amount >= ?", 10000)
	    .Find(&dogs)
    // 女神1号关联的狗哥 => [{1 狗哥1号 [] {1 10000 1}} {2 狗哥2号 [] {2 80000 2}}]
	fmt.Printf("女神1号关联的狗哥 => %v\n", dogs)
}

上述代码执行的SQL如下

SQL
SELECT `m2_m_dogs`.`id`,`m2_m_dogs`.`name` FROM `m2_m_dogs` 
JOIN dog_girl_god dg ON dg.m2_m_dog_id = m2_m_dogs.id 
JOIN m2_m_wallets w on w.m2_m_dog_id = m2_m_dogs.id 
WHERE dg.m2_m_girl_god_id = 1 AND w.amount >= 100001