主表字段中有一个子表的集合,子表存主表的关联id,类似于这样的结构:
//主表
type User struct{
ID int
Info []UserInfo //子表的数据
}
//子表
type UserInfo struct{
ID int
UserId int //主表的id
}
我之前不太会,都是两个表分别查,然后在拼接在一起,相当的麻烦
然后大佬给了个方法,查sql的时候用一下 Preload ,直接就出来了
//主表
type User struct{
ID int
Info []UserInfo `gorm:"foreignKey:UserId;"`
}
func(User) TableName()string{
return "user" //数据库对应的表名
}
//子表
type UserInfo struct{
ID int
UserId int
}
user := make([]*User,0)
err := global.GVA_DB.Preload("Info").Find(&user).Error
//Preload 里面的字段是Info,不是UserInfo
会生成两条SQL语句
SELECt * FROM `user_info` WHERe `user_info`.`user_id` IN (1,2,3,4) AND `user_info`.`deleted_at` IS NULL
SELECT * FROM `user` WHERe `user`.`deleted_at` IS NULL
学艺不精啊,虽然好像看过sql的预加载,但是完全想不起来用。不愧是大佬啊,感谢升哥
-------------------------------------------------------------------------------------------------------
今天又用到了这个,想写一个能连接三张表的Proload, 但是总是不对,怎么也查不出来,改成两个表的还是不行,只是告诉我 :unsupported relations,我来来回回看了好几遍gorm文档,也没看出来有啥问题,网上搜索也没找到怎么解决。。。然后看了我之前的代码,唯一的区别就是,写的时候没有加model。。。
//这个是之前的成功的
var customer []model.CustomerPack
err = global.GVA_DB.Where("id = ?",id).Preload("DistributePack").Find(&customer).Error
//然后是这个
var stowage []*response.StowageAreaGoods2
err = global.GVA_DB.Model(&model.stowage).Preload("CustomerPack").Preload("CustomerPack.DistributePack").Find(&stowage).Error
按照我之前的理解,db.model() 的作用就是确定表名,生成sql后的from ‘表名’ 就是model里面的结构体的tableName方法确定的。因为单查询生成的sql语句 和preload查询的sql完全一样,所以导致我完全搞不懂那里有错误,为何Preload是不支持的关系。
最后实验发现,加Model( ) 也可以,只是model里面的结构体必须和上面定义的相同,类似于:
var stowage []*response.StowageAreaGoods2
err = global.GVA_DB.Model(&response.StowageAreaGoods2{}).Preload("CustomerPack").Preload("CustomerPack.DistributePack").Find(&stowage).Error
那么db.model() 的作用也就明了了,确定各个结构体之间的关系,确定整体的结构,只是之前的查询都是单查询或者直接查视图,没有认识到model()的作用。
这样查出来的数据是三级的树形结构,同时需要在第二级按照其中一个“sequence”字段进行排序;如果直接加上 .Order() 方法是对第一级的stowage表排序,所以需要用到一个骚操作:
gorm实现多对多映射,以及预加载排序 - 简书
err = global.GVA_DB.
Preload("CustomerPack", func(db *gorm.DB) *gorm.DB{
return db.Order("sequence")
}).Preload("CustomerPack.DistributePack").Find(&stowage).Error
还可以这么写,不过第二种sql查询好像更加耗时
err = global.GVA_DB.
Preload("CustomerPack", func(db *gorm.DB) *gorm.DB{
return db.Order("sequence").Preload("DistributePack")
}).Find(&stowage).Error
生成的sql
二级的数据
SELECt * FROM `v_customer_pack` WHERe `v_customer_pack`.`stowage_id` IN (1,2,3) AND `v_customer_pack`.`deleted_at` IS NULL ORDER BY sequence三级的数据
SELECT * FROM `distribute_pack` WHERe `distribute_pack`.`customer_id` IN (3,1) AND `distribute_pack`.`deleted_at` IS NULL一级的数据
SELECT * FROM `stowage` WHERe `stowage`.`deleted_at` IS NULL
--------------------------------------------------------------------
Preload References 的用法
有种情况是 主子表不是通过主表id关联的
主表
type BackWarehouse struct {
ID uint `json:"id"`
BackNumber string `json:"backNumber" `
BackType string `json:"backType" `
BackStatus string `json:"backStatus" `
CustomerId uint `json:"customerId" `
TransportId uint `json:"transportId" `
OrderId uint `json:"orderId" `
}
子表
type OrderDetail struct {
ID uint `json:"id"`
OrderId int `json:"orderId" `
ProductId int `json:"productId" `
ProductCount int `json:"productCount"`
BackCount uint `json:"backCount" `
ProductCode string `json:"productCode"`
}
现在要用 OrderId 关联两个表
type BackOrder struct {
BackWarehouse
OrderDetail []*OrderDetail `json:"order" gorm:"foreignKey:OrderId;references:OrderId"`
}
references 的作用就是确定用哪个字段链接,但是也不能没有foreignKey,没有就会报错 :
invalid field found for struct com-psms-server/model.BackOrder's field OrderDetail, need to define a valid foreign key for relations or it need to implement the Valuer/Scanner interface
无法识别`OrderDetail` 字段



