Use the queryWrapper of mybatisPlus for subqueries (and the traditional xml method for leftjoin)

Like a many-to-many data table relationship, for example, the inspection package contains inspection groups, and the inspection groups contain inspection items. I want to make a setmeal object containing groupList, and groupu has itemList. How to write mybatis sql, and use mybatisPlus in java code how to write in

For the many-to-many data table relationship, in MyBatis, three tables are usually used to represent it. Taking the inspection package you mentioned includes inspection groups and inspection groups including inspection items as an example, we can use the following three tables to represent:

1. Check package table: t_setmeal, including basic information of check package, such as package name, price, etc.
2. Check group table: t_checkgroup, which is used to represent a check group in a check package, and a package can correspond to multiple check groups.
3. Check item table: t_checkitem, used to represent a check item in a check group, and a check group can correspond to multiple check items.

The following describes how to write SQL statements in MyBatis and MyBatis-Plus to query the inspection package and its inspection groups and inspection items.

## Implemented in MyBatis

### Query inspection packages and their inspection groups and inspection items```xml

<select id="findSetmealById" resultMap="setmealResultMap">
  SELECT s.id, s.name, s.code, s.helpCode, s.sex, s.age, s.price, s.remark, s.attention, s.img,
  g.id AS groupId, g.name AS groupName,
  i.id AS itemId, i.name AS itemName
  FROM t_setmeal s
  LEFT JOIN t_setmeal_checkgroup sc ON s.id = sc.setmeal_id
  LEFT JOIN t_checkgroup g ON sc.checkgroup_id = g.id
  LEFT JOIN t_checkgroup_checkitem gi ON g.id = gi.checkgroup_id
  LEFT JOIN t_checkitem i ON gi.checkitem_id = i.id
  WHERE s.id = #{id}
</select>

<resultMap id="setmealResultMap" type="Setmeal">
  <id property="id" column="id"/>
  <result property="name" column="name"/>
  <result property="code" column="code"/>
  <result property="helpCode" column="helpCode"/>
  <result property="sex" column="sex"/>
  <result property="age" column="age"/>
  <result property="price" column="price"/>
  <result property="remark" column="remark"/>
  <result property="attention" column="attention"/>
  <result property="img" column="img"/>
  <collection property="groupList" ofType="CheckGroup">
    <id property="id" column="groupId" />
    <result property="name" column="groupName" />
    <collection property="itemList" ofType="CheckItem">
      <id property="id" column="itemId" />
      <result property="name" column="itemName" />
    </collection>
  </collection>
</resultMap>


```

The above SQL statement uses JOIN multiple tables to query the relationship between inspection packages, inspection groups and inspection items through LEFT JOIN. The resultMap defines the mapping result, including the information of the inspection package, inspection group and inspection item, and defines the attributes of the collection type through the collection tag, and maps the inspection group and inspection item to the inspection package.

## Implemented in MyBatis-Plus

MyBatis-Plus provides a more convenient way to use than MyBatis, and can directly perform CRUD operations through entity objects without handwriting SQL. The following briefly describes how to implement the functions described above through MyBatis-Plus.

### Query inspection packages and their inspection groups and inspection items

For the convenience of operation, we need to create Mapper interface and Service interface corresponding to the entity class, and inherit the base class provided by MyBatis-Plus. Here is a code sample for the t_setmeal table: ```java

public interface SetmealMapper extends BaseMapper<Setmeal> {
}

public interface SetmealService extends IService<Setmeal> {
    Setmeal findSetmealById(Long id);
}

@Service
public class SetmealServiceImpl extends ServiceImpl<SetmealMapper, Setmeal> implements SetmealService {

    @Override
    public Setmeal findSetmealById(Long id) {
        Setmeal setmeal = baseMapper.selectById(id);
        List<CheckGroup> groupList = baseMapper.findGroupListBySetmealId(id);
        for (CheckGroup group : groupList) {
            List<CheckItem> checkItemList = baseMapper.findItemListByGroupId(group.getId());
            group.setItemList(checkItemList);
        }
        setmeal.setGroupList(groupList);
        return setmeal;
    }
}


```

In the above code, we use the BaseMapper interface and ServiceImpl class provided by MyBatis-Plus to easily implement the CRUD operation of the t_setmeal table, and use the custom method findSetmealById to query the inspection package and the inspection group and inspection item information it contains . In the findSetmealById method, two custom methods, findGroupListBySetmealId and findItemListByGroupId, are used to query the inspection group included in the inspection package and the inspection item information included in the inspection group respectively.

Regarding how to implement these two custom methods, the following is a code example of MyBatis XML Mapper: ```xml

<select id="findGroupListBySetmealId" resultMap="BaseResultMap">
    SELECT g.*
    FROM t_setmeal_checkgroup sc
    LEFT JOIN t_checkgroup g ON sc.checkgroup_id = g.id
    WHERE sc.setmeal_id = #{id,jdbcType=INTEGER}
</select>

<select id="findItemListByGroupId" resultMap="BaseResultMap">
    SELECT i.*
    FROM t_checkgroup_checkitem gi
    LEFT JOIN t_checkitem i ON gi.checkitem_id = i.id
    WHERE gi.checkgroup_id = #{id,jdbcType=INTEGER}
</select>


```

The above custom method uses two SQL statements to query the information of inspection groups and inspection items respectively, and defines the mapping results through resultMap.

Finally, we call the findSetmealById method in SetmealService to query the information about the inspection package and the inspection groups and inspection items it contains. MyBatis-Plus will automatically perform object mapping operations, and map query results into corresponding entity class objects.

Ok, here is the `findSetmealById` method implemented using MyBatis-Plus:```java

@Service
public class SetmealServiceImpl extends ServiceImpl<SetmealMapper, Setmeal> implements SetmealService {

    @Autowired
    private CheckGroupMapper checkGroupMapper;
    
    @Autowired
    private CheckItemMapper checkItemMapper;
    
    @Override
    public Setmeal findSetmealById(Long id) {
        Setmeal setmeal = this.getById(id);
        
        // 查询所有关联的检查组对象
        List<CheckGroup> groupList = checkGroupMapper.selectList(new QueryWrapper<CheckGroup>().inSql("id", "select checkgroup_id from t_setmeal_checkgroup where setmeal_id = "+id));
        for (CheckGroup group : groupList) {
            // 查询所有关联的检查项对象
            List<CheckItem> itemList = checkItemMapper.selectList(new QueryWrapper<CheckItem>().inSql("id", "select checkitem_id from t_checkgroup_checkitem where checkgroup_id = "+group.getId()));
            group.setItemList(itemList);
        }
        setmeal.setGroupList(groupList);
        
        return setmeal;
    }
}


```

In the above code, we use `this.getById(id)` method to query `setmeal` of inspection package object with specified ID. Then, we use `checkGroupMapper.selectList` method to query all associated inspection group objects `groupList` according to the relationship table between inspection packages and inspection groups (t_setmeal_checkgroup), and loop through each inspection group object, and then pass `checkItemMapper The .selectList` method queries all associated check item objects according to the relationship table between check groups and check items (t_checkgroup_checkitem), then sets the check item list to the check group object, and finally sets the check group list to the check package object , and return it.

It should be noted that when querying inspection groups and inspection items, we use the `inSql` method, because we need to query all eligible objects, instead of only querying one, but only use simple conditions such as `eq` The query method is not available.

In addition, it is necessary to inject the implementation classes of `CheckGroupMapper` and `CheckItemMapper` interfaces into the `SetmealServiceImpl` class. These two Mapper interfaces are used to operate the check group table and check item table.

If you want to use MyBatis to implement the above code logic, you can refer to my previous answer to your question.

Ok, so here is the sample code to override the above `findSetmealById` method using LambdaQueryWrapper:```java

@Service
public class SetmealServiceImpl extends ServiceImpl<SetmealMapper, Setmeal> implements SetmealService {

    @Autowired
    private CheckGroupMapper checkGroupMapper;

    @Autowired
    private CheckItemMapper checkItemMapper;

    @Override
    public Setmeal findSetmealById(Long id) {
        Setmeal setmeal = this.getById(id);

        // 使用 LambdaQueryWrapper 查询所有关联的检查组对象
        List<CheckGroup> groupList = checkGroupMapper.selectList(new LambdaQueryWrapper<CheckGroup>()
                .inSql(CheckGroup::getId, "select checkgroup_id from t_setmeal_checkgroup where setmeal_id = " + id));

        // 遍历所有关联的检查组对象并查询所有关联的检查项对象
        groupList.forEach(group -> {
            List<CheckItem> itemList = checkItemMapper.selectList(new LambdaQueryWrapper<CheckItem>()
                    .inSql(CheckItem::getId, "select checkitem_id from t_checkgroup_checkitem where checkgroup_id = " + group.getId()));
            group.setItemList(itemList);
        });

        setmeal.setGroupList(groupList);
        return setmeal;
    }
}


```

In the above code, we are using LambdaQueryWrapper when querying inspection groups and inspection items. Specifically, we use the `inSql` method to implement subqueries, and use the `LambdaQueryWrapper::inSql` method to avoid handwriting SQL and make the code more concise and easy to read.

Also, note that we used Lambda expressions for functional programming when iterating over all associated inspection group objects. Lambda expressions can make the code more concise and easy to maintain.

It should be reminded that to use LambdaQueryWrapper, the Lambda module of MyBatis-Plus needs to be introduced into the project.

```xml

<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-extension</artifactId>
    <version>${mybatis-plus.version}</version>
</dependency>


```

Yes, `inSql()` is one of the APIs in MyBatis-Plus for implementing subqueries. It allows us to nest a subquery and use the result set of the subquery as one of the query conditions, so as to achieve more flexible and complex SQL queries.

When using `inSql()`, we need to write a subquery statement first, map the result set to a certain field or entity class, and then pass the subquery statement as a parameter to the `inSql()` method. For example:

```java

QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.inSql("id", "select id from role where role_name like '管理员%'");
List<User> userList = userMapper.selectList(wrapper);


```

In the above code, we use the `inSql()` method to nest a subquery statement into the main query. The subquery statement obtains a set of role IDs through `select id from role where role_name like 'administrator%'`, and these role IDs will be passed to the second parameter in the `inSql()` method as a filter condition (that is, `id ` field). This query statement means to query the role ID whose role name starts with "administrator". Since the `inSql()` method itself does not support parameter binding, we need to hard-code the parameters in the subquery statement into the statement.

It is worth mentioning that there are other APIs for implementing subqueries in MyBatis-Plus, such as methods such as `apply()` and `exists()`. These APIs can be used to build complex SQL queries, and can help us improve query efficiency and reduce database pressure.

Guess you like

Origin blog.csdn.net/weixin_42759398/article/details/130498273