数据库中表经常会跟其他数据表有关联,数据操作时需要连同关联的表一起操作。如:一个博客文章会有分类、标签、评论,以及属于哪个用户。
ThinkJS 中支持关联模型,让处理这类操作非常简单。
关联模型中支持常见的 4 类关联关系。如:
think.model.HAS_ONE
一对一模型 think.model.BELONG_TO
一对一属于 think.model.HAS_MANY
一对多 think.model.MANY_TO_MANY
多对多 可以通过命令 thinkjs model [name] --relation
来创建关联模型。如:
thinkjs model home/post --relation
会创建模型文件 src/home/model/post.js
。
可以通过 relation
属性来指定关联关系。如:
export default class extends think.model.relation { init(...args){ super.init(...args); //通过 relation 属性指定关联关系,可以指定多个关联关系 this.relation = { cate: {}, comment: {} }; }}
也可以直接使用 ES7 里的语法直接定义 relation
属性。如:
export default class extends think.model.relation { //直接定义 relation 属性 relation = { cate: {}, comment: {} }; init(...args){ super.init(...args); }}
export default class extends think.model.relation { init(...args){ super.init(...args); this.relation = { cate: { type: think.model.MANY_TO_MANY, //relation type model: "", //model name name: "profile", //data name key: "id", fKey: "user_id", //forign key field: "id,name", where: "name=xx", order: "", limit: "", rModel: "", rfKey: "" }, }; }}
各个字段含义如下:
type
关联关系类型 model
关联表的模型名,默认为配置的 key,这里为 cate
name
对应的数据字段名,默认为配置的 key,这里为 cate
key
当前模型的关联 key fKey
关联表与只对应的 key field
关联表查询时设置的 field,如果需要设置,必须包含 fKey
对应的值 where
关联表查询时设置的 where 条件 order
关联表查询时设置的 order limit
关联表查询时设置的 limit page
关联表查询时设置的 page rModel
多对多下,对应的关联关系模型名 rfKey
多对多下,对应里的关系关系表对应的 key 如果只用设置关联类型,不用设置其他字段信息,可以通过下面简单的方式:
export default class extends think.model.relation { init(...args){ super.init(...args); this.relation = { cate: think.model.MANY_TO_MANY }; }}
一对一关联,表示当前表含有一个附属表。
假设当前表的模型名为 user
,关联表的模型名为 info
,那么配置中字段 key
的默认值为 id
,字段 fKey
的默认值为 user_id
。
export default class extends think.model.relation { init(..args){ super.init(...args); this.relation = { info: think.model.HAS_ONE }; }}
执行查询操作时,可以得到类似如下的数据:
[ { id: 1, name: "111", info: { //关联表里的数据信息 user_id: 1, desc: "info" } }, ...]
一对一关联,属于某个关联表,和 HAS_ONE 是相反的关系。
假设当前模型名为 info
,关联表的模型名为 user
,那么配置字段 key
的默认值为 user_id
,配置字段 fKey
的默认值为 id
。
export default class extends think.model.relation { init(..args){ super.init(...args); this.relation = { user: think.model.BELONG_TO }; }}
执行查询操作时,可以得到类似下面的数据:
[ { id: 1, user_id: 1, desc: "info", user: { name: "thinkjs" } }, ...]
一对多的关系。
加入当前模型名为 post
,关联表的模型名为 comment
,那么配置字段 key
默认值为 id
,配置字段 fKey
默认值为 post_id
。
"use strict";/** * relation model */export default class extends think.model.relation { init(...args){ super.init(...args); this.relation = { comment: { type: think.model.HAS_MANY } }; }}
执行查询数据时,可以得到类似下面的数据:
[{ id: 1, title: "first post", content: "content", comment: [{ id: 1, post_id: 1, name: "welefen", content: "first comment" }, ...]}, ...]
如果关联表的数据需要分页查询,可以通过 page
参数进行,如:
"use strict";/** * relation model */export default class extends think.model.relation { init(...args){ super.init(...args); this.relation = { comment: { type: think.model.HAS_MANY } }; } getList(page){ return this.setRelation("comment", {page: page}).select(); }}
除了用 setRelation
来合并参数外,可以将参数设置为函数,合并参数时会自动执行该函数。
多对多关系。
假设当前模型名为 post
,关联模型名为 cate
,那么需要一个对应的关联关系表。配置字段 rModel
默认值为 post_cate
,配置字段 rfKey
默认值为 cate_id
。
"use strict";/** * relation model */export default class extends think.model.relation { init(...args){ super.init(...args); this.relation = { cate: { type: think.model.MANY_TO_MANY, rModel: "post_cate", rfKey: "cate_id" } }; }}
查询出来的数据结构为:
[{ id: 1, title: "first post", cate: [{ id: 1, name: "cate1", post_id: 1 }, ...]}, ...]
如果 2 个关联表,一个设置对方为 HAS_ONE,另一个设置对方为 BELONG_TO,这样在查询关联表的数据时会将当前表又查询了一遍,并且会再次查询关联表,最终导致死循环。
可以在配置里设置 relation
字段关闭关联表的关联查询功能,从而避免死循环。如:
export default class extends think.model.relation { init(..args){ super.init(...args); this.relation = { user: { type: think.model.BELONG_TO, relation: false //关联表 user 查询时关闭关联查询 } }; }}
也可以设置只关闭当前模型的关联关系,如:
export default class extends think.model.relation { init(..args){ super.init(...args); this.relation = { user: { type: think.model.BELONG_TO, relation: "info" //关联表 user 查询时关闭对 info 模型的关联关系 } }; }}
设置关联关系后,查询等操作都会自动查询关联表的数据。如果某些情况下不需要查询关联表的数据,可以通过 setRelation
方法临时关闭关联关系查询。
通过 setRelation(false)
关闭所有的关联关系查询。
export default class extends think.model.relation { init(...args){ super.init(...args); this.relation = { comment: think.model.HAS_MANY, cate: think.model.MANY_TO_MANY }; } getList(){ return this.setRelation(false).select(); }}
通过 setRelation('comment')
只查询 comment
的关联数据,不查询其他的关联关系数据。
export default class extends think.model.relation { init(...args){ super.init(...args); this.relation = { comment: think.model.HAS_MANY, cate: think.model.MANY_TO_MANY }; } getList2(){ return this.setRelation("comment").select(); }}
通过 setRelation('comment', false)
关闭 comment
的关联关系数据查询。
export default class extends think.model.relation { init(...args){ super.init(...args); this.relation = { comment: think.model.HAS_MANY, cate: think.model.MANY_TO_MANY }; } getList2(){ return this.setRelation("comment", false).select(); }}
通过 setRelation(true)
重新启用所有的关联关系数据查询。
export default class extends think.model.relation { init(...args){ super.init(...args); this.relation = { comment: think.model.HAS_MANY, cate: think.model.MANY_TO_MANY }; } getList2(){ return this.setRelation(true).select(); }}
设置 field 可以控制查询关联表时数据字段,这样可以减少查询的数据量,提高查询查询效率。默认情况会查询所有数据。
如果设置了查询的字段,那么必须包含关联字段,否则查询出来的数据无法和之前的数据关联。
export default class extends think.model.relation { init(...args){ super.init(...args); this.relation = { user: { type: think.model.BELONG_TO, field: "id,name,email" //必须要包含关联字段 id } }; }}
如果某些情况下必须动态的设置的话,可以将 field 设置为一个函数,执行函数时返回对应的字段。如:
export default class extends think.model.relation { init(...args){ super.init(...args); this.relation = { user: { type: think.model.BELONG_TO, field: model => { return model._relationField; } } }; } selectData(relationfield){ //将要查询的关联字段设置到一个私有属性中,便于动态设置 field 里获取 this._relationField = relationfield; return this.select(); }}
形参 model
指向当前模型类。
设置 where 可以控制查询关联表时的查询条件,如:
export default class extends think.model.relation { init(...args){ super.init(...args); this.relation = { user: { type: think.model.BELONG_TO, where: { grade: 1 //只查询关联表里 grade = 1 的数据 } } }; }}
也可以动态的设置 where 条件,如:
export default class extends think.model.relation { init(...args){ super.init(...args); this.relation = { user: { type: think.model.BELONG_TO, where: model => { return model._relationWhere; } } }; } selectData(relationWhere){ this._relationWhere = relationWhere; return this.select(); }}
形参 model
指向当前模型类。
可以通过设置 page 进行分页查询,page 参数会被解析为 limit 数据。
export default class extends think.model.relation { init(...args){ super.init(...args); this.relation = { user: { type: think.model.BELONG_TO, page: [1, 15] //第一页,每页 15 条 } }; }}
也可以动态设置分页,如:
export default class extends think.model.relation { init(...args){ super.init(...args); this.relation = { user: { type: think.model.BELONG_TO, page: model => { return model._relationPage; } } }; } selectData(page){ this._relationPage = [page, 15]; return this.select(); }}
形参 model
指向当前模型类。
可以通过 limit 设置查询的条数,如:
export default class extends think.model.relation { init(...args){ super.init(...args); this.relation = { user: { type: think.model.BELONG_TO, limit: [10] //限制 10 条 } }; }}
也可以动态设置 limit,如:
export default class extends think.model.relation { init(...args){ super.init(...args); this.relation = { user: { type: think.model.BELONG_TO, limit: model => { return model._relationLimit; } } }; } selectData(){ this._relationLimit = [1, 15]; return this.select(); }}
形参 model
指向当前模型类。
注: 如果设置 page
,那么 limit
会被忽略,因为 page
会转为 limit
。
通过 order 可以设置关联表的查询排序方式,如:
export default class extends think.model.relation { init(...args){ super.init(...args); this.relation = { user: { type: think.model.BELONG_TO, order: "level DESC" } }; }}
也可以动态的设置 order,如:
export default class extends think.model.relation { init(...args){ super.init(...args); this.relation = { user: { type: think.model.BELONG_TO, order: model => { return model._relationOrder; } } }; } selectData(){ this._relationOrder= "level DESC"; return this.select(); }}
形参 model
指向当前模型类。
注
:动态配置值从 2.2.3
版本开始支持。
联系客服