通过在entity或者vo的属性注解,可以关联查询并自动组装数据,不需要写任何xml和sql语句,生成的sql语句不使用join,而是使用索引in查询,java的stream进行组装,解决mybatis多表关联时可能存在的n+1问题 使用mybatis-plus的接口,可以和现有项目无侵入整合
zhuyunlong2018/mybatis-plus-relations: mybatis-plus的关联模型查询插件 (github.com)
mybatis-plus-relations: mybatis-plus的关联查询,使用注解方式操作 (gitee.com)
添加maven依赖
<dependency>
<groupId>io.gitee.zhuyunlong2018</groupId>
<artifactId>mybatis-plus-relations-core</artifactId>
<version>1.0.4</version>
</dependency>
给SpringBoot入口程序添加@RelationScan注解即可,包名可以实现和@MapperScan一样的通配符操作,*代表一级通配符,**代表可以多级通配符,用于扫描含有关联查询注解的entity或者vo等
@SpringBootApplication
@MapperScan(basePackages = "com.gitee.zhuyunlong2018.mybatisplusrelations.**.mapper")
@RelationScan({
"com.gitee.zhuyunlong2018.mybatisplusrelations.*.vo",
"com.gitee.zhuyunlong2018.mybatisplusrelations.entity"
})
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@Data
@EqualsAndHashCode(callSuper = true)
@Accessors(chain = true)
@ToString(callSuper = true)
public class DeptVo extends Dept {
// 通过注解绑定关联,localProperty为当前entity的关联属性,foreignProperty为被关联进来的entity的关联属性
@BindMany(localProperty = "deptId", foreignProperty = "deptId")
private List<User> users;
public DeptVo(Dept dept) {
super(dept);
}
}
先在UserVO添加@BindOne注解绑定关联方式
@Data
@NoArgsConstructor
public class UserVO extends User {
@BindOne(localProperty = "deptId", foreignProperty = "id")
private Dept dept;
}
service中进行绑定
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
/**
* 查询单个用户信息
*/
@Override
public UserVO getOneUser(Integer userId) {
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class)
.eq(User::getId, userId);
UserVO userVo = EntityUtils.toObj(getOne(wrapper), UserVO::new);
// 此处进行绑定操作
Relations.with(userVo).bindOne(UserVO::getDept).end();
return userVo;
}
/**
* 批量查询用户信息
*/
@Override
public List<UserVO> getUserByList() {
// 先查询用户信息(表现形式为列表)
List<User> user = list(Wrappers.emptyWrapper());
List<UserVO> userVos = user.stream().map(UserVO::new).collect(toList());
// 此处进行绑定操作
Relations.with(userVos).bindOne(UserVO::getDept).end();
return userVos;
}
}
先在模型进行绑定@BindMany注解
@Data
public class DeptVO extends Dept {
@BindMany(localProperty = "id", foreignProperty = "deptId")
private List<User> users;
public DeptVO(Dept dept) {
super(dept);
}
}
service中进行绑定
/**
* @author explore
* @since 2021/05/24 11:09
**/
@Service
public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements IDeptService {
/**
* 查询单个部门
*/
@Override
public DeptVO getOneDept(Integer deptId) {
LambdaQueryWrapper<Dept> wrapper = Wrappers.lambdaQuery(Dept.class).eq(Dept::getId, deptId);
DeptVO deptVo = EntityUtils.toObj(getOne(wrapper), DeptVO::new);
// 此处进行绑定操作
Relations.with(deptVo).bindMany(DeptVO::getUsers).end();
return deptVo;
}
/**
* 查询多个部门
*/
@Override
public List<DeptVO> getDeptByList() {
List<DeptVO> deptVos = EntityUtils.toList(list(Wrappers.emptyWrapper()), DeptVO::new);
// 此处进行绑定操作
Relations.with(deptVos).bindMany(DeptVO::getUsers).end();
return deptVos;
}
}
先在模型进行绑定@ManyBindMany注解
@Data
@NoArgsConstructor
public class UserVO extends User {
@ManyBindMany(
localProperty = "id",
foreignProperty = "id",
linkModel = UserSkillRelation.class,
linkLocalProperty = "userId",
linkForeignProperty = "skillId",
iterateLinkMethod = "setUserSkillScope"
)
private List<SkillVO> skills;
/**
* 中间表迭代器 relations的size总是保持和skills的size一样
* @param relations
*/
public void setUserSkillScope(List<UserSkillRelation> relations) {
for (int i = 0; i < relations.size(); i++) {
this.skills.get(i).setScore(relations.get(i).getScore());
}
}
}
service中进行绑定
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
/**
* 查询单个用户信息
*/
@Override
public UserVO getOneUser(Integer userId) {
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class)
.eq(User::getId, userId);
UserVO userVo = EntityUtils.toObj(getOne(wrapper), UserVO::new);
// 此处进行绑定操作
Relations.with(userVo).manyBindMany(UserVO::getSkills).end();
return userVo;
}
/**
* 批量查询用户信息
*/
@Override
public List<UserVO> getUserByList() {
// 先查询用户信息(表现形式为列表)
List<User> user = list(Wrappers.emptyWrapper());
List<UserVO> userVos = user.stream().map(UserVO::new).collect(toList());
// 此处进行绑定操作
Relations.with(userVos).manyBindMany(UserVO::getSkills).end();
return userVos;
}
}
@ManyBindMany可以实现多对多绑定,并且实现了IManyBindHandler接口的linkQuery方法,可以对中间表的query进行过滤查询 用户和技能表示多对多关联,在manyBindMany后,可以进行linkQuery,此方法传递的是中间表的LambdaQueryWrapper,可以对中间表进行过滤检索
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
@Override
public List<UserVO> getUserByList() {
List<User> user = list(Wrappers.emptyWrapper());
List<UserVO> userVos = user.stream().map(UserVO::new).collect(toList());
// 此步骤可以有多个
Relations.with(userVos)
.manyBindMany(UserVO::getSkills)
.linkQuery((LambdaQueryWrapper<UserSkillRelation> wrapper) -> {
wrapper.gt(UserSkillRelation::getScore, 90);
})
.end();
return userVos;
}
}
@ManyBindMany注解有一个iterateLinkMethod迭代器属性,可以传入主模型的一个方法,对中间表进行迭代操作,详情可以查阅上面的模型代码,让模型可以获取到中间表的数据进行一些操作
@BindOne、@BindMany、@ManyBindMany三个注解除了在注解时可以追加applySql和lastSql外,还可以在service中进行绑定,如下
@Service
public class DeptServiceImpl extends ServiceImpl<DeptMapper, Dept> implements IDeptService {
@Override
public List<DeptVO> getDeptByList() {
// 按条件查询部门信息
List<DeptVO> deptVos = EntityUtils.toList(list(Wrappers.emptyWrapper()), DeptVO::new);
// query方法可以过滤副表user的ID为1
Relations.with(deptVos)
.bindMany(DeptVO::getUsers)
.query(wrapper -> wrapper.eq(User::getUserId, 1))
.end();
return deptVos;
}
}
IBinder提供一个deepBinder的方法,可以将副表的绑定器继续绑定新的关联属性,实现递归绑定操作
模型关系,一个用户有多项技能关联表,每个技能关联表UserSkillVO又关联了一个技能属性Skill
@Data
@NoArgsConstructor
public class UserVO extends User {
@BindMany(localProperty = "id", foreignProperty = "userId")
private List<UserSkillVO> userSkills;
}
@Data
public class UserSkillVO extends UserSkillRelation {
@BindOne(localProperty = "skillId", foreignProperty = "id")
private Skill skill;
}
具体业务代码,用户模型先bindMany检索出所有的关联数据,再通过deepWith获得副表的Binder,追加绑定副表的关系
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
@Override
public UserVO getOneUser(Integer userId) {
LambdaQueryWrapper<User> wrapper = Wrappers.lambdaQuery(User.class)
.eq(User::getId, userId);
UserVO userVo = EntityUtils.toObj(getOne(wrapper), UserVO::new);
Relations.with(userVo)
.bindMany(UserVO::getUserSkills)
.deepWith(binder -> {
binder.bindOne(UserSkillVO::getSkill)
.end();
})
.end();
return userVo;
}
}
具体包含以下几个步骤:
restart.include.relations=/io.gitee.zhuyunlong2018.*.jar
mvn clean deploy -pl mybatis-plus-relations-core -am
如果终端无法弹出密码输入框,出现gpg: signing failed: Inappropriate ioctl for device
错误,运行如下命令
export GPG_TTY=$(tty)
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。