使用mybatisPlus的queryWrapper进行子查询(以及传统xml方式做leftjoin)

像多对多的数据表关系,比如检查套餐包含检查组,检查组包含检查项,我要想做一个setmeal对象包含groupList,而gropu有itemList,写mybatis的sql怎么写,而用mybatisPlus在java代码里应该怎么写

对于多对多的数据表关系,在 MyBatis 中,通常会使用三张表来表示。以你提到的检查套餐包含检查组、检查组包含检查项为例,我们可以使用如下三张表来表示:

1. 检查套餐表:t_setmeal,包含检查套餐的基本信息,如套餐名称、价格等等。
2. 检查组表:t_checkgroup,用于表示一个检查套餐中的一个检查组,一个套餐可以对应多个检查组。
3. 检查项表:t_checkitem,用于表示一个检查组中的一个检查项,一个检查组可以对应多个检查项。

下面分别介绍在 MyBatis 和 MyBatis-Plus 中,如何写 SQL 语句来查询检查套餐及其包含的检查组和检查项信息。

## 在 MyBatis 中实现

### 查询检查套餐及其包含的检查组和检查项```xml




  
  
  
  
  
  
  
  
  
  
  
    
    
    
      
      
    
  


```

上面的 SQL 语句使用了 JOIN 多张表,通过 LEFT JOIN 的方式来查询出检查套餐、检查组和检查项之间的关系。其中 resultMap 定义了映射结果,包含了检查套餐、检查组和检查项的信息,并通过 collection 标签来定义了集合类型的属性,把检查组和检查项映射到检查套餐中。

## 在 MyBatis-Plus 中实现

MyBatis-Plus 提供了比 MyBatis 更加简便的使用方式,可以通过实体对象直接进行 CRUD 操作,无需手写 SQL。以下简述如何通过 MyBatis-Plus 实现上面所述的功能。

### 查询检查套餐及其包含的检查组和检查项

为了方便操作,我们需要创建与实体类对应的 Mapper 接口和 Service 接口,并继承 MyBatis-Plus 提供的基类。以下是针对 t_setmeal 表的代码示例:```java

public interface SetmealMapper extends BaseMapper {
}

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

@Service
public class SetmealServiceImpl extends ServiceImpl implements SetmealService {

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


```

在上面的代码中,我们利用了 MyBatis-Plus 提供的 BaseMapper 接口和 ServiceImpl 类,简便地实现了 t_setmeal 表的 CRUD 操作,并且通过自定义方法 findSetmealById 来查询检查套餐及其包含的检查组和检查项信息。findSetmealById 方法中使用了两个自定义方法 findGroupListBySetmealId 和 findItemListByGroupId,分别查询检查套餐包含的检查组和检查组包含的检查项信息。

关于如何实现这两个自定义方法,以下是 MyBatis XML Mapper 的代码示例:```xml




```

上面的自定义方法使用了两个 SQL 语句,分别查询检查组和检查项的信息,并通过 resultMap 定义了映射结果。

最后,我们通过调用 SetmealService 中的 findSetmealById 方法来查询检查套餐及其包含的检查组和检查项信息。MyBatis-Plus 会自动进行对象的映射操作,将查询结果映射成对应的实体类对象。

好的,以下是使用 MyBatis-Plus 实现的 `findSetmealById` 方法:```java

@Service
public class SetmealServiceImpl extends ServiceImpl implements SetmealService {

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


```

在上述代码中,我们通过 `this.getById(id)` 方法来查询指定 ID 的检查套餐对象 `setmeal`。然后,我们通过 `checkGroupMapper.selectList` 方法,根据检查套餐与检查组之间的关系表(t_setmeal_checkgroup) 查询所有关联的检查组对象 `groupList`,并通过循环遍历每个检查组对象,再通过 `checkItemMapper.selectList` 方法,根据检查组与检查项之间的关系表(t_checkgroup_checkitem)查询所有关联的检查项对象,然后将检查项列表设置到检查组对象中,最后将检查组列表设置到检查套餐对象中,并返回它。

需要注意的是,在查询检查组和检查项的时候,我们使用了 `inSql` 方法,这是因为我们需要查询所有符合条件的对象,而不是只查询一个,而只使用 `eq` 等简单条件查询方法是无法实现的。

另外,需要在 `SetmealServiceImpl` 类中注入 `CheckGroupMapper` 和 `CheckItemMapper` 接口的实现类,这两个 Mapper 接口用于操作检查组表和检查项表。

如果要使用 MyBatis 实现以上代码逻辑,可以参考我之前回答你的问题时的答案。

好的,那么这里是使用 LambdaQueryWrapper 重写上述 `findSetmealById` 方法的示例代码:```java

@Service
public class SetmealServiceImpl extends ServiceImpl implements SetmealService {

    @Autowired
    private CheckGroupMapper checkGroupMapper;

    @Autowired
    private CheckItemMapper checkItemMapper;

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

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

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

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


```

在上述代码中,我们在查询检查组和检查项时使用了 LambdaQueryWrapper。具体来说,我们使用 `inSql` 方法来实现子查询,使用 `LambdaQueryWrapper::inSql` 方法可以避免手写 SQL,使代码更加简洁易读。

另外,需要注意的是,在遍历所有关联的检查组对象时,我们使用了 Lambda 表达式进行函数式编程。lambda 表达式可以使代码更加简洁,易于维护。

需要提醒的是,要使用 LambdaQueryWrapper,需要在项目中引入 MyBatis-Plus 的 Lambda 模块。

```xml


    com.baomidou
    mybatis-plus-extension
    ${mybatis-plus.version}


```

是的,`inSql()`是MyBatis-Plus中用于实现子查询的API之一。它允许我们嵌套一个子查询,将子查询的结果集作为查询条件之一,从而实现更加灵活和复杂的 SQL 查询。

使用 `inSql()` 时,我们需要先编写子查询语句,将结果集映射到某个字段或实体类中,再将子查询语句作为参数传递给 `inSql()` 方法中。例如:

```java

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


```

上述代码中,我们使用 `inSql()` 方法将一个子查询语句嵌套到主查询中。该子查询语句通过 `select id from role where role_name like '管理员%'` 获得一组角色ID,这些角色ID会作为过滤条件传递给 `inSql()` 方法中的第二个参数(即 `id` 字段)。该查询语句的意思是,查询角色名称以“管理员”开头的角色ID。由于 `inSql()` 方法本身不支持参数绑定,我们需要将子查询语句中的参数硬编码到语句中。

值得一提的是,MyBatis-Plus 中还有其他用于实现子查询的 API,如 `apply()`和`exists()`等方法。这些 API 均可用于构建复杂的 SQL 查询,并能帮助我们提升查询效率和减少数据库压力。

你可能感兴趣的:(xml,mybatis,java)