Go-gorm returns 如果使用字段中具有默认值的 Struct 实例过滤的所有记录
Go-gorm returns all records if filtered with Struct instance that has default Value in a field
假设我们有以下结构:
type Task struct {
...
Completed bool `gorm:"default:false" json:"-"`
}
MySQL 数据库中有 5 个条目:
- 其中 2 个
Completed=1
- 其中 3 个
Completed=0
我面临以下特点:
db, err = gorm.Open("mysql", connstr)
var ret []Task
// This returns 3 rows
db.Debug().Model(&Task{}).Find(&ret, "Completed =?", false)
// This returns 2 rows
db.Debug().Model(&Task{}).Find(&ret, Task{Completed: true})
// BUT THIS RETURNS 5 ROWS!
db.Debug().Model(&Task{}).Find(&ret, Task{Completed: false})
知道为什么会这样吗?在最后一次调用时执行的 SQL 是:
SELECT * FROM 'tasks'
我想避免为每个结构字段编写新的 SQL 查询。传递结构(对象)似乎更明智。
原因
GORM 查看提供给 Find()
的结构字段,并检查设置了哪些字段,以构建查询。因此在第二个示例中,它看到 Completed
设置为 true
,并向查询添加 WHERE 子句:
db.Debug().Model(&Task{}).Find(&ret, Task{Completed: true})
生成:
SELECT * FROM "tasks" WHERE "tasks"."completed" = true
在第二个示例中,GORM 无法知道您是传入了 Task{Completed: false}
还是简单地传入了 Task{}
,因为 false
是 [=21] 的 zero-value =].
如果您有一个 int
字段并尝试查询 0
:
,同样的事情也会发生
db.Debug().Model(&Task{}).Find(&ret, Task{Num: 0}) // Generates: SELECT * FROM 'tasks'
解决方案
如果您真的想使用该结构进行查询,您可以更改模型,使 Completed
成为 *bool
而不是 bool
。由于指针的 零值 为 nil,提供指向 false 的指针将告诉 GORM 添加该子句:
trueBool := true
falseBool := false
db.Debug().Model(&Task{}).Find(&ret, Task{Completed: &falseBool})
db.Debug().Model(&Task{}).Find(&ret, Task{Completed: &trueBool})
生成(分别)
SELECT * FROM "tasks" WHERE "tasks"."completed" = false
SELECT * FROM "tasks" WHERE "tasks"."completed" = true
请记住,这样做意味着如果未设置 Completed
可以在数据库中保存为 NULL
。
假设我们有以下结构:
type Task struct {
...
Completed bool `gorm:"default:false" json:"-"`
}
MySQL 数据库中有 5 个条目:
- 其中 2 个
Completed=1
- 其中 3 个
Completed=0
我面临以下特点:
db, err = gorm.Open("mysql", connstr)
var ret []Task
// This returns 3 rows
db.Debug().Model(&Task{}).Find(&ret, "Completed =?", false)
// This returns 2 rows
db.Debug().Model(&Task{}).Find(&ret, Task{Completed: true})
// BUT THIS RETURNS 5 ROWS!
db.Debug().Model(&Task{}).Find(&ret, Task{Completed: false})
知道为什么会这样吗?在最后一次调用时执行的 SQL 是:
SELECT * FROM 'tasks'
我想避免为每个结构字段编写新的 SQL 查询。传递结构(对象)似乎更明智。
原因
GORM 查看提供给 Find()
的结构字段,并检查设置了哪些字段,以构建查询。因此在第二个示例中,它看到 Completed
设置为 true
,并向查询添加 WHERE 子句:
db.Debug().Model(&Task{}).Find(&ret, Task{Completed: true})
生成:
SELECT * FROM "tasks" WHERE "tasks"."completed" = true
在第二个示例中,GORM 无法知道您是传入了 Task{Completed: false}
还是简单地传入了 Task{}
,因为 false
是 [=21] 的 zero-value =].
如果您有一个 int
字段并尝试查询 0
:
db.Debug().Model(&Task{}).Find(&ret, Task{Num: 0}) // Generates: SELECT * FROM 'tasks'
解决方案
如果您真的想使用该结构进行查询,您可以更改模型,使 Completed
成为 *bool
而不是 bool
。由于指针的 零值 为 nil,提供指向 false 的指针将告诉 GORM 添加该子句:
trueBool := true
falseBool := false
db.Debug().Model(&Task{}).Find(&ret, Task{Completed: &falseBool})
db.Debug().Model(&Task{}).Find(&ret, Task{Completed: &trueBool})
生成(分别)
SELECT * FROM "tasks" WHERE "tasks"."completed" = false
SELECT * FROM "tasks" WHERE "tasks"."completed" = true
请记住,这样做意味着如果未设置 Completed
可以在数据库中保存为 NULL
。