那些年XORM踩过的坑

警告
本文最后更新于 2024-03-26,文中内容可能已过时。

XORM会将字段名称为ID的,类型为int64的字段默认为该表的主键,如果将ID字段类型设置为int类型,则不会被自动识别为该表的主键。

1
2
3
type Table struct {
	Id                  int  `json:"id"`       // 自增ID
}
  • 如果在插入一条数据时,插入成功后直接返回该记录的自增ID,则必须将该model的结构体ID设置为int64类型
  • 结构体的ID字段上面的tag,不能设置xorm:"id"这个标签,如果设置了这个标签,则会默认ID为0,不会返回插入成功后的主键ID。XORM文档也有相关的描述:在插入单条数据成功后,如果该结构体有自增字段(设置为AUTO_INCREMENT),则自增字段会被自动赋值为数据库中的ID。这里需要注意的是,如果插入的结构体中,自增字段已经赋值,则该字段会被作为非自增字段插入。

修改数据答题可以分为两种方式,一种是通过model进行修改,一种是通过map[string]**interface{}来进行修改的,作者平常主要使用的是第二种方式,所以也主要介绍该种方法。

1
2
3
4
5
6
7
8
9
	// 更新字段
	up := make(map[string]interface{})
	up["begin_time"] = common.StrToUnixTimeDay(req.StartTime)
	up["end_time"] = common.StrToUnixTimeDay(req.EndTime)

	// 更新数据
	_, err = session.Table("table").
		Where("id = ?", req.Id).
		Update(up)

该方式可以通过在map中添加和数据库表中相同的字段的键值对,来达到更新相应字段的效果,但是需要注意,使用这种方式更新数据时,需要指定表名


XORMFindAndCount()函数确实好用省事,但是却不能通用,全部使用这个方法,一些情况会导致函数的count()部分失效(使用分组函数、进行连表查询等),所以需要具体情况具体分析,选用合适的方法进行查询。

1
2
3
4
total, err := relation.Where("car.id = ?", req.ContractId).
		Where("car.is_del = 1").
		Limit(req.Limit, (req.Page-1)*req.Limit).
		FindAndCount(&respList)

原先一直用的ORM框架是GORM,所以第一次使用XORM的时候,习惯性的使用了Where("id in ?", ids)来进行查询,一用直接就报错,后面排查了一下,发现XORM不支持这种写法,之后又研究了下其他的写法,第一种就是最简单的使用原生支持的In()函数来进行搜索,还有就是通过原生的SQL拼接的方法进行的In操作,但是这种方法也有一个坑。哎…

1
2
3
4
// 下面是原生拼接的两种类型

t1.id IN (1,2,3,4)     		// 这是正确的写法:可以获取多个值
t1.id IN ("1, 2, 3, 84")  	// 这是错误的写法,只能获取一个值,默认会是第一个值,也就是 1
  • 使用XORM,进行原生SQL拼接查询
1
2
3
4
`t1.id IN ( ? )`

// 这样写,会将 in 里面的值用""包装(字符串),sql 最终就变成上面的错误写法
ml, err = xorm.Engine().Query(sql + in + order, idsStr)
  • 解决方案
1
2
// 直接这样拼接,会得到上面的正确的写法,得到正确结果
`t1.id IN (`+strings.Join(idsStr,",")+`)`