MyBatis-plus implementa consulta de enlace de tres niveles, procesamiento de consulta de tabla conjunta que implica paginación y consulta difusa

1. Vinculación a tres niveles (tomando como ejemplo provincia-ciudad-sala de examen)

1) diseño de mesa

La misma tabla existe para provincias y ciudades. Un parentId de 0 representa una provincia, y un parentId distinto de cero representa una ciudad dentro de la provincia correspondiente.

package com.example.jiakao.pojo.entity;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import javax.persistence.*;

@Entity
@Data
@TableName("plate_region")
@Table(name="plate_region")
public class PlateRegionPo {
    @Id
    @TableId(type = IdType.AUTO)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column( columnDefinition = "int4" )
    private Integer id;
    @Column( columnDefinition = "varchar(64)" )
    private String name;
    @Column( columnDefinition = "varchar(64)" )
    private String plate;
    @Column( columnDefinition = "int4 default 0 " )
    private Integer parentId;
}

 Mesa de la sala de examen, parentId corresponde a la identificación de la ciudad

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;

import javax.persistence.*;

@Entity
@Data
@TableName("exam_place")
@Table(name="exam_place")
public class ExamPlacePo {
    @Id
    @TableId(type = IdType.AUTO)
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column( columnDefinition = "bigint" )
    private Long id;
    @Column( columnDefinition = "varchar(64)" )
    private String name;
    @Column( columnDefinition = "int4" )
    private Integer parentId;
}

2) Definir el tipo de retorno vo

package com.example.jiakao.pojo.vo.list;

import lombok.Data;

import java.util.List;

@Data
public class ProvinceVo {
    private Long id;
    private String name;
    private String plate;
    private List<CityVo> children;
}
package com.example.jiakao.pojo.vo.list;

import lombok.Data;

import java.util.List;

@Data
public class CityVo {
    private Long id;
    private String name;
    private String plate;
    private List<ExamPlaceVo> children;
}
package com.example.jiakao.pojo.vo.list;

import lombok.Data;

@Data
public class ExamPlaceVo {
    private Long id;
    private String name;
}

3) instrucción de consulta mapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.jiakao.mapper.ExamPlacePoMapper">
    <resultMap id="selectRegionExamPlaces" type="com.example.jiakao.pojo.vo.list.ProvinceVo">
        <id column="id" property="id"></id>
        <result column="name" property="name"></result>
        <result column="plate" property="plate"></result>
        <collection property="children" ofType="com.example.jiakao.pojo.vo.list.CityVo">
            <id column="city_id" property="id"></id>
            <result column="city_name" property="name"></result>
            <result column="city_plate" property="plate"></result>
            <collection property="children" ofType="com.example.jiakao.pojo.vo.list.ExamPlaceVo">
                <id column="exam_id" property="id"></id>
                <result column="exam_name" property="name"></result>
            </collection>
        </collection>

    </resultMap>
    <select id="listRegionExamPlaces" resultMap="selectRegionExamPlaces">
        select
            p.id,
            p.name,
            p.plate,
            c.id city_id,
            c.name city_name,
            c.plate city_plate,
            e.id exam_id,
            e.name exam_name
        from plate_region p
            join plate_region c on c.parent_id = p.id
            join exam_place e on e.parent_id = c.id
        where p.parent_id = 0
    </select>
</mapper>

4) Resultados de la consulta

{
    "code": 200,
    "message": "成功",
    "data": [
        {
            "id": 2,
            "name": "湖北",
            "plate": "鄂",
            "children": [
                {
                    "id": 3,
                    "name": "武汉",
                    "plate": "A",
                    "children": [
                        {
                            "id": 1,
                            "name": "hfgg"
                        },
                        {
                            "id": 5,
                            "name": "hgi"
                        }
                    ]
                }
            ]
        },
        {
            "id": 1,
            "name": "广东",
            "plate": "粤",
            "children": [
                {
                    "id": 7,
                    "name": "深圳",
                    "plate": "B",
                    "children": [
                        {
                            "id": 6,
                            "name": "hgiG"
                        }
                    ]
                },
                {
                    "id": 8,
                    "name": "广州",
                    "plate": "A",
                    "children": [
                        {
                            "id": 7,
                            "name": "hgU"
                        },
                        {
                            "id": 8,
                            "name": "hgUU"
                        }
                    ]
                }
            ]
        }
    ]
}

5) Puntos a tener en cuenta

        La diferencia entre combinación, combinación izquierda y combinación derecha se resume brevemente: la combinación toma la intersección de dos tablas y solo conserva las entradas de la intersección; la combinación izquierda usa la tabla anterior a la combinación como tabla principal, independientemente de si hay una intersección o no, las entradas de la tabla principal existen; la combinación derecha toma la tabla después de la combinación como la tabla principal.

2. Sobre el procesamiento de consultas de tablas conjuntas con consulta difusa y paginación (tomando como ejemplo las asignaturas de sala de examen-examen)

1) La definición de vo se usa para pasar parámetros al guardar datos, correspondientes a los campos del objeto po, y solo ignora los campos en el objeto po que no requieren la operación del usuario.

package com.example.jiakao.pojo.vo.req.save;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

@Data
@ApiModel("保存考场信息的参数")
public class ExamPlaceReqVo {
    @ApiModelProperty(value = "考场id")
    private Long id;
    @ApiModelProperty(value = "考场名称", required = true)
    @NotBlank(message = "名称不能为空")
    private String name;
    @ApiModelProperty(value = "考场所属城市id", required = true)
    @NotNull(message = "所属城市不能为空")
    private Integer cityId;
    @ApiModelProperty(value = "考场所属省份id", required = true)
    @NotNull(message = "所属省份不能为空")
    private Integer provinceId;
}
package com.example.jiakao.pojo.vo.req.save;

import com.example.jiakao.common.validator.BoolNumber;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;

@Data
@ApiModel("保存课程信息")
public class ExamCourseReqVo {
    @ApiModelProperty("课程id")
    private Long id;
    @ApiModelProperty(value = "课程名称", required = true)
    @NotBlank(message = "课程名不能为空")
    private String name;
    @ApiModelProperty(value = "课程类型",required = true)
    @NotNull(message = "课程类型不能为空")
    @BoolNumber(message = "课程类型值为0或1")
    private Short type;
    @ApiModelProperty(value = "课程价格",required = true)
    @NotNull(message = "课程价格不能为空")
    @Min(value = 0, message = "价格不能为负数")
    private Double price;
    @ApiModelProperty(value = "课程所属考场",required = true)
    @NotNull(message = "所属考场不能为空")
    private Long examPlaceId;
}

 La definición de vo de la lista de devolución se utiliza para construir la entidad de resultado de devolución.

package com.example.jiakao.pojo.vo.list;

import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

@Data
@ApiModel("课程信息返回值")
public class ExamCourseVo {
    @ApiModelProperty("课程id")
    private Long id;
    @ApiModelProperty(value = "课程名称")
    private String name;
    @ApiModelProperty(value = "课程类型")
    private Short type;
    @ApiModelProperty(value = "课程价格")
    private Double price;
    @ApiModelProperty(value = "课程所属考场")
    private Long examPlaceId;
    @ApiModelProperty(value = "考场所属省份")
    private Integer provinceId;
    @ApiModelProperty(value = "考场所属城市")
    private Integer cityId;
}

2) Servicio y Mapeador

        Debido a que hay campos de nombre en las dos tablas que usamos, debemos marcar claramente el campo de nombre de qué tabla al construir QueryWrapper, por lo que aquí usamos QueryWrapper en lugar de LambdaQueryWrapper.

package com.example.jiakao.service;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.jiakao.common.enhance.MpPage;
import com.example.jiakao.common.enhance.MpQueryWrapper;
import com.example.jiakao.mapper.ExamCourseMapper;
import com.example.jiakao.pojo.entity.ExamCoursePo;
import com.example.jiakao.pojo.vo.json.PageVo;
import com.example.jiakao.pojo.vo.list.ExamCourseVo;
import com.example.jiakao.pojo.vo.req.query.KeyWordReqVo;
import org.springframework.stereotype.Service;

@Service
public class ExamCourseService extends ServiceImpl<ExamCourseMapper, ExamCoursePo> {
    public PageVo<ExamCourseVo> listCoursesPage(KeyWordReqVo query) {
        MpPage<ExamCourseVo> mpPage= new MpPage<>(query);
        MpQueryWrapper<ExamCourseVo> wrapper = new MpQueryWrapper<>();
        wrapper.likes(query.getKeyword(),"c.name");
        baseMapper.selectCourses(mpPage,wrapper);
        return mpPage.buildVo();
    }
}  }
}
package com.example.jiakao.mapper;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.Constants;
import com.example.jiakao.common.enhance.MpPage;
import com.example.jiakao.pojo.entity.ExamCoursePo;
import com.example.jiakao.pojo.vo.list.ExamCourseVo;
import org.apache.ibatis.annotations.Param;

//官方推荐前缀Constants.WRAPPER => ew
public interface ExamCourseMapper extends BaseMapper<ExamCoursePo> {
    public MpPage<ExamCourseVo> selectCourses(MpPage<ExamCourseVo> page,
                                              @Param(Constants.WRAPPER) QueryWrapper wrapper);
}

        Cuando el tipo que pasamos y devolvemos en el método Mapper es la implementación de la interfaz IPage, Mybatis-plus automáticamente nos ayudará a paginar, es decir, empalmar el límite después de la declaración de consulta. Sin embargo, las condiciones de consulta no se implementarán automáticamente para nosotros. Necesitamos llamar manualmente al customSqlSegment del tipo QueryWrapper para obtener la declaración SQL y luego empalmarla en xml. Tenga en cuenta que ${} se usa para empalmar en lugar de #{}, $ es un reemplazo directo y # se compilará previamente.

        Por supuesto, también podemos construir LambdaQueryWrapper para entidades personalizadas que no sean entidades genéricas de BaseMapper cuando sea necesario. En este caso, necesitamos agregar la configuración afterPropertiesSet.

public class MyBatisPlusConfig implements InitializingBean {
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.POSTGRE_SQL));
        return interceptor;
    }

    /**
     * 拥有lambda cache的实体类,才能使用LambdaQueryWrapper<Entity>
     * 默认情况下只有BaseMapper<Entity>中泛型的entity才拥有lambda cache
     * 其他可以通过TableInfoHelper手动添加lambda cache
     */
    @Override
    public void afterPropertiesSet() throws Exception {
        MapperBuilderAssistant assistant = new MapperBuilderAssistant(new MybatisConfiguration(),"");
        TableInfoHelper.initTableInfo(assistant, ExamCourseVo.class);
    }
}

3)Mapeador.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.jiakao.mapper.ExamCourseMapper">
    <resultMap id="selectCourses" type="com.example.jiakao.pojo.vo.list.ExamCourseVo">
    </resultMap>
<!--    ${wrapper.customSqlSegment} 获取自定义SQL-->
    <select id="selectCourses" resultMap="selectCourses">
        select
            c.id,
            c.name,
            c.exam_place_id,
            c.price,
            c.type,
            e.city_id,
            e.province_id
        from exam_course c
            left join exam_place e on c.exam_place_id = e.id
        ${ew.customSqlSegment}
    </select>
</mapper>

Supongo que te gusta

Origin blog.csdn.net/qq_33235279/article/details/130319445
Recomendado
Clasificación