GORM 的使用 - 2
在 raw SQL 中指定 table name 和 index name
GORM 支持使用 raw SQL,不过有个问题,就是使用字符串传递 index name 或者 table name 时,会被自动加上单引号 (Postgres driver)。例如下面的代码:
// DB wraps gorm.DB object to provides more methods.
type DB struct {
*gorm.DB
}
func (db *DB) CreateBucketObjectTable(bucket *Bucket) (err error) {
tableName := bucket.ObjectTableName()
if err = db.Table(tableName).Migrator().CreateTable(new(Object)); err != nil {
return err
}
err = db.Exec(`CREATE UNIQUE INDEX ? ON ? ("key")`,
fmt.Sprintf("idx_%s_key", tableName), tableName).Error
if err != nil {
return nil
}
return nil
}
最终会执行的 SQL 语句是
CREATE UNIQUE INDEX 'idx_bucket_1_key' ON 'bucket_1' ("key");
因为 index name 和 table name 都被自动加上了单引号,所以数据库那边会返回错误,类似: ERROR: syntax error at or near “$1” (SQLSTATE 42601)
这个问题是因为 GORM 为了安全起见,在生成语句时,如果 ?
占位符对应的是字符串,都自动加上了单引号。解决这个问题的办法是使用 gorm/clause 中的数据类型,如下所示:
import (
"fmt"
"gorm.io/gorm/clause"
)
func (db *DB) CreateBucketObjectTable(bucket *Bucket) (err error) {
tableName := bucket.ObjectTableName()
if err = db.Table(tableName).Migrator().CreateTable(new(Object)); err != nil {
return err
}
index := clause.Table{Name: fmt.Sprintf("idx_%s_key", tableName)}
table := clause.Table{Name: tableName}
err = db.Exec(`CREATE UNIQUE INDEX ? ON ? ("key")`, index, table).Error
if err != nil {
return err
}
return nil
}
这里我们明确了 ?
占位符对应的是表名,所以生成的语句会变成:
CREATE UNIQUE INDEX "idx_bucket_1_key" ON "bucket_1" ("key");
