多级一对一关系表使用Joins查询出错
- 使用 #3282 问题的回复处理报错, 源码内好像只有对主表的关联关系有判断
- 加连表sql又查询不到结果, 我看源码对字段解析好像只有一级表关系使用"__"做处理.
这是我的表接口以及具体查询
type User struct {
ID int64 `gorm:"primary_key;autoIncrement" json:"id"`
Name string `gorm:"column:name;" json:"name"`
}
type Order struct {
ID int64 `gorm:"primary_key;autoIncrement" json:"id"`
SerialNo string `gorm:"not null; column:serialNo" json:"serialNo"`
UserId int64 `gorm:"not null; column:userId;" json:"userId"`
User *User `gorm:"foreignKey:userId"`
}
type OrderShipping struct {
ID int64 `gorm:"primary_key;autoIncrement" json:"id"`
Note string `gorm:"column: note;" json:"note"`
OrderId int64 `gorm:"not null; column:orderId;" json:"orderId"`
Order *Order `gorm:"foreignKey:orderId"`
}
func (op *OrderShipping) FindAll() {
// 直接join
tx := DB.Debug().Model(op).Joins("Order").Joins("User").Find(&op)
if tx.Error != nil {
fmt.Printf("tx err is: %+v\n", tx.Error)
}
// 打印出的错误:
// tx err is: Error 1064: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'User' at line 1
// 加关联
tx2 := DB.Debug().Model(op).
Joins("Order"). //.Joins("User").Find(&op)
Joins("LEFT JOIN `users` AS `User` ON `Order`.`userId` = `User`.`id`").
Select("`order_shippings`.*, `Order`.*, `User`.*").
Find(&op)
if tx2.Error != nil {
fmt.Printf("tx2 err is: %+v\n", tx2.Error)
}
fmt.Printf("op: %+v\n", op.Order)
fmt.Printf("op.Order.User: %+v\n", op.Order.User)
// op.Order.User 为 nil
}
sql
INSERT INTO users (id, name) VALUES (1, 'tom');
INSERT INTO orders (id, serialNo, userId) VALUES (1, '123456', 1);
INSERT INTO order_shippings (id, ` note`, orderId) VALUES (1, 'notes....', 1);
Expected answer
需要怎样才能通过Joins的方式正常的查询到User表中的数据?
Comment From: wxy2077
你的结构体 column写的有问题,MySQL字段命名习惯是下划线。 对于你这个需求,直接用预加载Preload就可以解决。
以下是我的例子 gorm_demo_test.go
package test
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
"testing"
)
type User struct {
ID int64 `gorm:"primaryKey;autoIncrement;column:id;type:INT;" json:"id"`
Name string `gorm:"column:name;" json:"name"`
}
func (u *User) TableName() string {
return "users"
}
type Order struct {
ID int64 `gorm:"primaryKey;autoIncrement;column:id;type:INT;" json:"id"`
SerialNo string `gorm:"not null; column:serial_no" json:"serial_no"`
UserId int64 `gorm:"not null; column:user_id;" json:"user_id"`
User *User `gorm:"foreignKey:UserId;references:ID" json:"user"`
}
func (o *Order) TableName() string {
return "orders"
}
type OrderShipping struct {
ID int64 `gorm:"primaryKey;autoIncrement;column:id;type:INT;" json:"id"`
Note string `gorm:"column:note;" json:"note"`
OrderId int64 `gorm:"column:order_id;" json:"order_id"`
Order *Order `gorm:"foreignKey:OrderId;references:ID" json:"order"`
}
func (o *OrderShipping) TableName() string {
return "order_shippings"
}
func (o *OrderShipping) FindAll(db *gorm.DB) (list []*OrderShipping) {
list = make([]*OrderShipping, 0)
db.Debug().Model(&OrderShipping{}).Preload("Order", func(tx *gorm.DB) *gorm.DB {
return tx.Preload("User")
}).Find(&list)
return list
}
func Test_CRUD(t *testing.T) {
db, err := gorm.Open(mysql.New(mysql.Config{
DSN: "root:123456@tcp(127.0.0.1:3306)/gozero?charset=utf8mb4&parseTime=True&loc=Local", // DSN data source name
DefaultStringSize: 256, // string 类型字段的默认长度
DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持
DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引
DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列
SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置
}), &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)})
if err != nil {
panic(err)
}
list := new(OrderShipping).FindAll(db)
t.Log(list[0]) // &{1 notes.... 1 0xc000406cf0}
t.Log(list[0].Order) // &{1 123456 1 0xc0001e9680}
t.Log(list[0].Order.User.Name) // tom
// INSERT INTO users (id, name) VALUES (1, 'tom');
// INSERT INTO orders (id, serial_no, user_id) VALUES (1, '123456', 1);
// INSERT INTO order_shippings (id, note, order_id) VALUES (1, 'notes....', 1);
}
Comment From: jinzhu
joins doesn't works with multiple levels
Comment From: runningzyp
@sankforever
Comment From: DarckRM
你的结构体 column写的有问题,MySQL字段命名习惯是下划线。 对于你这个需求,直接用预加载Preload就可以解决。
以下是我的例子
gorm_demo_test.go```go package test
import ( "gorm.io/driver/mysql" "gorm.io/gorm" "gorm.io/gorm/logger" "testing" )
type User struct { ID int64
gorm:"primaryKey;autoIncrement;column:id;type:INT;" json:"id"Name stringgorm:"column:name;" json:"name"}func (u *User) TableName() string { return "users" }
type Order struct { ID int64
gorm:"primaryKey;autoIncrement;column:id;type:INT;" json:"id"SerialNo stringgorm:"not null; column:serial_no" json:"serial_no"UserId int64gorm:"not null; column:user_id;" json:"user_id"User *Usergorm:"foreignKey:UserId;references:ID" json:"user"}func (o *Order) TableName() string { return "orders" }
type OrderShipping struct { ID int64
gorm:"primaryKey;autoIncrement;column:id;type:INT;" json:"id"Note stringgorm:"column:note;" json:"note"OrderId int64gorm:"column:order_id;" json:"order_id"Order *Ordergorm:"foreignKey:OrderId;references:ID" json:"company_user"}func (o *OrderShipping) TableName() string { return "order_shippings" }
func (o OrderShipping) FindAll(db gorm.DB) (list []*OrderShipping) {
list = make([]OrderShipping, 0) db.Debug().Model(&OrderShipping{}).Preload("Order", func(tx gorm.DB) *gorm.DB { return tx.Preload("User") }).Find(&list)
return list }
func Test_CRUD(t *testing.T) { db, err := gorm.Open(mysql.New(mysql.Config{ DSN: "root:123456@tcp(127.0.0.1:3306)/gozero?charset=utf8mb4&parseTime=True&loc=Local", // DSN data source name DefaultStringSize: 256, // string 类型字段的默认长度 DisableDatetimePrecision: true, // 禁用 datetime 精度,MySQL 5.6 之前的数据库不支持 DontSupportRenameIndex: true, // 重命名索引时采用删除并新建的方式,MySQL 5.7 之前的数据库和 MariaDB 不支持重命名索引 DontSupportRenameColumn: true, // 用
change重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列 SkipInitializeWithVersion: false, // 根据当前 MySQL 版本自动配置 }), &gorm.Config{Logger: logger.Default.LogMode(logger.Silent)}) if err != nil { panic(err) }list := new(OrderShipping).FindAll(db)
t.Log(list[0]) // &{1 notes.... 1 0xc000406cf0} t.Log(list[0].Order) // &{1 123456 1 0xc0001e9680} t.Log(list[0].Order.User.Name) // tom
// INSERT INTO users (id, name) VALUES (1, 'tom'); // INSERT INTO orders (id, serial_no, user_id) VALUES (1, '123456', 1); // INSERT INTO order_shippings (id, note, order_id) VALUES (1, 'notes....', 1);
} ```
感谢,你的代码解决我的问题了
Comment From: wxy2077
感谢,你的代码解决我的问题了
哈哈哈,那挺好的,gorm基础使用我写了一些例子,仓库在这里,你可以参考参考。
https://github.com/wxy2077/gorm-example