• Join的使用

    Join的使用

    • Join(string,interface{},string)

    第一个参数为连接类型,当前支持INNER, LEFT OUTER, CROSS中的一个值,第二个参数为string类型的表名,表对应的结构体指针或者为两个值的[]string,表示表名和别名,第三个参数为连接条件。

    以下将通过示例来讲解具体的用法:

    假如我们拥有两个表user和group,每个User只在一个Group中,那么我们可以定义对应的struct

    1. type Group struct {
    2. Id int64
    3. Name string
    4. }
    1. type User struct {
    2. Id int64
    3. Name string
    4. GroupId int64 `xorm:"index"`
    5. }

    OK。问题来了,我们现在需要列出所有的User,并且列出对应的GroupName。利用extends和Join我们可以比较优雅的解决这个问题。代码如下:

    1. type UserGroup struct {
    2. User `xorm:"extends"`
    3. Name string
    4. }
    5. func (UserGroup) TableName() string {
    6. return "user"
    7. }
    8. users := make([]UserGroup, 0)
    9. engine.Join("INNER", "group", "group.id = user.group_id").Find(&users)

    这里我们将User这个匿名结构体加了xorm的extends标记(实际上也可以是非匿名的结构体,只要有extends标记即可),这样就减少了重复代码的书写。实际上这里我们直接用Sql函数也是可以的,并不一定非要用Join。

    1. users := make([]UserGroup, 0)
    2. engine.Sql("select user.*, group.name from user, group where user.group_id = group.id").Find(&users)

    然后,我们忽然发现,我们还需要显示Group的Id,因为我们需要链接到Group页面。这样又要加一个字段,算了,不如我们把Group也加个extends标记吧,代码如下:

    1. type UserGroup struct {
    2. User `xorm:"extends"`
    3. Group `xorm:"extends"`
    4. }
    5. func (UserGroup) TableName() string {
    6. return "user"
    7. }
    8. users := make([]UserGroup, 0)
    9. engine.Join("INNER", "group", "group.id = user.group_id").Find(&users)

    这次,我们把两个表的所有字段都查询出来了,并且赋值到对应的结构体上了。

    这里要注意,User和Group分别有Id和Name,这个是重名的,但是xorm是可以区分开来的,不过需要特别注意UserGroup中User和Group的顺序,如果顺序反了,则有可能会赋值错误,但是程序不会报错。

    这里的顺序应遵循如下原则:

    1. 结构体中extends标记对应的结构顺序应和最终生成SQL中对应的表出现的顺序相同。

    还有一点需要注意的,如果在模板中使用这个UserGroup结构体,对于字段名重复的必须加匿名引用,如:

    对于不重复字段,可以{{.GroupId}},对于重复字段{{.User.Id}}{{.Group.Id}}

    这是2个表的用法,3个或更多表用法类似,如:

    1. type Type struct {
    2. Id int64
    3. Name string
    4. }
    5. type UserGroupType struct {
    6. User `xorm:"extends"`
    7. Group `xorm:"extends"`
    8. Type `xorm:"extends"`
    9. }
    10. users := make([]UserGroupType, 0)
    11. engine.Table("user").Join("INNER", "group", "group.id = user.group_id").
    12. Join("INNER", "type", "type.id = user.type_id").
    13. Find(&users)

    同时,在使用Join时,也可同时使用Where和Find的第二个参数作为条件,Find的第二个参数同时也允许为各种bean来作为条件。Where里可以是各个表的条件,Find的第二个参数只是被关联表的条件。

    1. engine.Table("user").Join("INNER", "group", "group.id = user.group_id").
    2. Join("INNER", "type", "type.id = user.type_id").
    3. Where("user.name like ?", "%"+name+"%").Find(&users, &User{Name:name})

    当然,如果表名字太长,我们可以使用别名:

    1. engine.Table("user").Alias("u").
    2. Join("INNER", []string{"group", "g"}, "g.id = u.group_id").
    3. Join("INNER", "type", "type.id = u.type_id").
    4. Where("u.name like ?", "%"+name+"%").Find(&users, &User{Name:name})