Code Monkey home page Code Monkey logo

mybatis-plus-join's Introduction

Mybatis-Plus-Join-Logo

MyBatis-Plus-Join

为简化开发工作、提高生产率而生

maven code style

MyBatis-Plus 多表查询的扩展 | 演示工程 | 使用文档 | 点个Star支持一下吧 (☆▽☆)

QQ群:680016987 或者 添加作者微信,备注MPJ,加入微信群
添加作者微信,备注MPJ,加入微信群

使用方法

安装

  • Maven
    <dependency>
        <groupId>com.github.yulichang</groupId>
        <artifactId>mybatis-plus-join-boot-starter</artifactId>
        <version>1.4.12</version>
    </dependency>
  • Gradle
     implementation 'com.github.yulichang:mybatis-plus-join-boot-starter:1.4.12'
    
    或者clone代码到本地执行 mvn install, 再引入以上依赖

    注意: MyBatis Plus版本需要3.3.0+

使用

  • mapper继承MPJBaseMapper (必选)
  • service继承MPJBaseService (可选)
  • serviceImpl继承MPJBaseServiceImpl (可选)

Lambda形式用法(MPJLambdaWrapper)

简单的连表查询

class test {
    @Resource
    private UserMapper userMapper;

    void testJoin() {
        //和Mybatis plus一致,MPJLambdaWrapper的泛型必须是主表的泛型,并且要用主表的Mapper来调用
        MPJLambdaWrapper<UserDO> wrapper = JoinWrappers.lambda(UserDO.class)
                .selectAll(UserDO.class)//查询user表全部字段
                .select(UserAddressDO::getTel)//查询user_address tel 字段
                .selectAs(UserAddressDO::getAddress, UserDTO::getUserAddress)//别名
                .select(AreaDO::getProvince, AreaDO::getCity)
                .leftJoin(UserAddressDO.class, UserAddressDO::getUserId, UserDO::getId)
                .leftJoin(AreaDO.class, AreaDO::getId, UserAddressDO::getAreaId)
                .eq(UserDO::getId, 1)
                .like(UserAddressDO::getTel, "1")
                .gt(UserDO::getId, 5);

        //连表查询 返回自定义ResultType
        List<UserDTO> list = userMapper.selectJoinList(UserDTO.class, wrapper);

        //分页查询 (需要启用 mybatis plus 分页插件)
        Page<UserDTO> listPage = userMapper.selectJoinPage(new Page<>(2, 10), UserDTO.class, wrapper);
    }
}

对应sql

SELECT  
    t.id, t.name, t.sex, t.head_img, 
    t1.tel, t1.address AS userAddress,
    t2.province, t2.city 
FROM 
    user t 
    LEFT JOIN user_address t1 ON t1.user_id = t.id 
    LEFT JOIN area t2 ON t2.id = t1.area_id 
WHERE (
    t.id = ? 
    AND t1.tel LIKE ? 
    AND t.id > ?)

说明:

  • UserDTO.class 查询结果返回类(resultType)
  • selectAll() 查询指定实体类的全部字段
  • select() 查询指定的字段,支持可变参数,同一个select只能查询相同表的字段
  • selectAs() 字段别名查询,用于数据库字段与业务实体类属性名不一致时使用
  • leftJoin() 参数说明
    第一个参数: 参与连表的实体类class
    第二个参数: 连表的ON字段,这个属性必须是第一个参数实体类的属性
    第三个参数: 参与连表的ON的另一个实体类属性
  • 默认主表别名是t,其他的表别名以先后调用的顺序使用t1,t2,t3....
  • 条件查询,可以查询主表以及参与连接的所有表的字段,全部调用mp原生的方法,正常使用没有sql注入风险

一对多查询

class test {
    @Resource
    private UserMapper userMapper;

    @Test
    void testResultMap() {
        MPJLambdaWrapper<UserDO> wrapper = new MPJLambdaWrapper<>(User.class)
                .selectAll(UserDO.class)
                //对多查询
                .selectCollection(AddressDO.class, UesrDTO::getAddressList)
                //对一查询
                .selectAssociation(AddressDO.class, UesrDTO::getAddress)
                .leftJoin(AddressDO.class, AddressDO::getUserId, UserDO::getId);

        List<UserDTO> dtoList = userMapper.selectJoinList(UserDTO.class, wrapper);

        //关于对多分页查询
        //由于嵌套结果方式会导致结果集被折叠,因此分页查询的结果在折叠后总数会减少,所以无法保证分页结果数量正确。
    }
}

MPJLambdaWrapper其他功能

mybatis-plus-join's People

Contributors

git-403 avatar luckey-ke avatar tuine avatar yulichang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

mybatis-plus-join's Issues

MPJLambdaWrapper 空指针异常

多对多查询,三表left join,出现以下问题

Caused by: org.apache.ibatis.ognl.OgnlException: from [java.lang.NullPointerException: Cannot invoke "com.baomidou.mybatisplus.core.metadata.TableInfo.getTableName()" because the return value of "com.baomidou.mybatisplus.core.metadata.TableInfoHelper.getTableInfo(java.lang.Class)" is null]
Caused by: java.lang.NullPointerException: Cannot invoke "com.baomidou.mybatisplus.core.metadata.TableInfo.getTableName()" because the return value of "com.baomidou.mybatisplus.core.metadata.TableInfoHelper.getTableInfo(java.lang.Class)" is null

已经在entity上加了@TableName

表如下

@Data
@TableName("table_a")
public class TableA {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
}

@Data
@TableName("table_b")
public class TableB {
    @TableId(type = IdType.AUTO)
    private Long id;
    private String name;
}


@Data
@TableName("table_a_b")
public class TableAB{
    private Long aId;
    private Long bId;
}

查询

 var page = new Page<TableA>(1, 2);
var pages = TableAMapper.selectJoinPage(page, TableA.class, new MPJLambdaWrapper<TableA>()
                 .selectAll(TableA.class)
                .leftJoin(TableAB.class, TableAB::getAId, TableA::getId)
                .leftJoin(TableB.class, TableB::getId, TableAB::getBId));

jdk:

openjdk 17.0.4.1 2022-08-12 LTS
OpenJDK Runtime Environment Corretto-17.0.4.9.1 (build 17.0.4.1+9-LTS)
OpenJDK 64-Bit Server VM Corretto-17.0.4.9.1 (build 17.0.4.1+9-LTS, mixed mode, sharing)

mybatis plus 、mybatis plus join 、spring boot 版本

	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.7.4</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
...
	<dependency>
			<groupId>com.baomidou</groupId>
			<artifactId>mybatis-plus-boot-starter</artifactId>
			<version>3.5.2</version>
		</dependency>

		<dependency>
			<groupId>com.github.yulichang</groupId>
			<artifactId>mybatis-plus-join</artifactId>
			<version>1.2.4</version>
		</dependency>

希望leftjoin同一个表的时候,别名可以不重复,或者允许自定义别名

我这条sql会报错,因为别名重复,连接了两次sys_dictionary表,但是别名都是一样的
IPage<HiddenTroubleVo> page = hiddenTroubleMapper.selectJoinPage( new Page<HiddenTroubleVo>(param.getPage(), param.getLimit()), HiddenTroubleVo.class, new MPJLambdaWrapper<HiddenTrouble>() .selectAll(HiddenTrouble.class) .selectAs(SysDictionary::getName, HiddenTroubleVo::getTypeName) .selectAs(User::getName, HiddenTroubleVo::getCreateUserName) .selectAs(SysDictionary::getName, HiddenTroubleVo::getStatusName) .leftJoin(SysDictionary.class, (on) -> on.eq(SysDictionary::getValue, HiddenTrouble::getType) .eq(SysDictionary::getType, SysDictionaryType.HIDDEN_TROUBLE_TYPE) ) .leftJoin(User.class, User::getId, HiddenTrouble::getCreateUser) .leftJoin(ServiceAgency.class, ServiceAgency::getId, HiddenTrouble::getServiceAgencyId) .leftJoin(SysDictionary.class, (on) -> on.eq(SysDictionary::getValue, HiddenTrouble::getType) .eq(SysDictionary::getType, SysDictionaryType.HIDDEN_TROUBLE_STATUS) ) );

MybatisPlusJoinAutoConfiguration 的 ConditionalOnClass 存在问题

MybatisPlusJoinAutoConfiguration 的每个方法上都使用了 @ConditionalOnClass, 如果只引入了 'mybatis-plus-join-boot-starter-1.4.5` 而没有引入 mybatis 相关的依赖的话, 会找不到 class (虽然业务开发中很少存在这种情况, 不过为了保障健壮性, 应该可以优化一下)

group by 字段问题

platform和merchant是一对多关系。
做关联count+group的时候,需要格式化结果, groupBy函数不够自然或者存在bug

        MPJLambdaWrapper<Merchant> qw = new MPJLambdaWrapper<>();
        qw.selectCount(Merchant::getId, CandidateValue::getValue);
        qw.selectAs(Platform::getName, CandidateValue::getTitle);
//        qw.groupBy(CandidateValue::getTitle); // 报错 mapper not find by class <CandidateValue>
//        qw.groupBy(Platform::getName); // 报错, sql 是GROUP BY t.name,应该是title
        qw.groupBy("title"); // ok,但是不如上面的两种方式自然
        qw.leftJoin(Platform.class, Platform::getId, Merchant::getPlatform);

selectJoinCount 报错, java.lang.Integer cannot be cast to java.lang.Long

  • 版本
    <mybatis-plus-join.version>1.4.3</mybatis-plus-join.version>
  • 描述
    测试selectJoinCount, 抛出异常,日志上看数据库执行都成功了。内部转换失败。测试日志如下
Creating a new SqlSession
SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4f664bee] was not registered for synchronization because synchronization is not active
JDBC Connection [HikariProxyConnection@1238145834 wrapping com.mysql.cj.jdbc.ConnectionImpl@6befbb12] will not be managed by Spring
==>  Preparing: SELECT COUNT( * ) FROM certificate_revocation t LEFT JOIN crl_operation t2 on t2.revocation_id = t.id WHERE (t.id = ?)
==> Parameters: 1(Integer)
<==    Columns: COUNT( * )
<==        Row: 5
<==      Total: 1
Closing non transactional SqlSession [org.apache.ibatis.session.defaults.DefaultSqlSession@4f664bee]

java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long

	at com.sun.proxy.$Proxy93.selectJoinCount(Unknown Source)
	at com.cicv.ma.common.db.mapper.RepoTest.joinTest(RepoTest.java:74)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
  • 测试代码如下
@Test
    public void joinTest() {
        MPJLambdaWrapper lambw = new MPJLambdaWrapper<>()
                .leftJoin(CrlOperation.class, CrlOperation::getRevocationId, CertificateRevocation::getId)
                .eq(CertificateRevocation::getId, 1);

        System.out.println(revocationService.selectJoinCount(qw).longValue());
    }

Invalid bound statement (not found)

Hello,

When running the package I get the following error:
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): {packagename}.{entity}Dao.selectJoinPage
at org.apache.ibatis.binding.MapperMethod$SqlCommand.(MapperMethod.java:235)
at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.(MybatisMapperMethod.java:51)
at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.lambda$cachedInvoker$0(MybatisMapperProxy.java:111)
at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660)
at com.baomidou.mybatisplus.core.toolkit.CollectionUtils.computeIfAbsent(CollectionUtils.java:117)
at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.cachedInvoker(MybatisMapperProxy.java:98)
at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89)
at com.sun.proxy.$Proxy158.selectJoinPage(Unknown Source)

I am running MybatisPlus 3.4.2 with mybatis-plus-join-boot-starter 1.3.11

Online I only find answers that advise me to move my mapper.xml but just like in the example, I don't use an xml.

Thank you in advance!

集成以后,找不到plus-join里面的方法

报错信息如下
org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.xxx.customer.core.mapper.CusCustomerMapper.selectJoinList;

mybatis-plus-join用的1.0.8
mybatis-plus 版本3.4.0

这个是自定义配置
@bean
@order(-2)
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

    interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
    //连表插件
    interceptor.addInnerInterceptor(new MPJInterceptor());
    return interceptor;
}

关键是这行
interceptor.addInnerInterceptor(new MPJInterceptor());
如果不把他加进去 运行时会报classCaseError

升级mybatis-plus-join版本的话,这行代码又显示无法转换MPJInterceptor类为MybatisPlusInterceptor 。只能降版本来用,好不容易项目起来了,原有sql也没问题。结果又出现了标题的报错信息。

具体原因未知,勉强点了一个星星

selectPageDeep 是否支持嵌套递归查询

比如 UserA 有个属性 Contact 用了 FieldMapping , Contact 内又有个 Email 属性用了 FieldMapping ,支持递归吗?
如果支持,那嵌套深度有限制吗(可能会出现无限递归)

业务上无法再使用 SqlInjector

因为 MybatisPlusJoinAutoConfiguration.mpjSqlInjector 和 MybatisPlusJoinAutoConfiguration.mpjSqlInjectorOnMiss 会创建 ISqlInjector 的实例, 然而如果业务代码也需要创建 ISqlInjector 的时间, 就会导致存在多个 bean:

Unsatisfied dependency expressed through bean property 'sqlSessionFactory'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in class path resource [com/baomidou/mybatisplus/autoconfigure/MybatisPlusAutoConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.apache.ibatis.session.SqlSessionFactory]: Factory method 'sqlSessionFactory' threw exception; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.baomidou.mybatisplus.core.injector.ISqlInjector' available: expected single matching bean but found 2: mpjSqlInjectorOnMiss,sqlInjector

在maven中添加mybatis-plus-join-boot-starter后package过程中自动配置类报错

2023-04-27 17:03:46.550 WARN 54268 --- [ main] o.s.w.c.s.GenericWebApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'mpjSpringContent' defined in class path resource [com/github/yulichang/autoconfigure/MybatisPlusJoinAutoConfiguration.class]: Unsatisfied dependency expressed through method 'mpjSpringContent' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.github.yulichang.autoconfigure.MybatisPlusJoinAutoConfiguration$MPJSpringContext' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}

2023-04-27 17:03:46.606 INFO 54268 --- [ main] c.b.d.d.DynamicRoutingDataSource : dynamic-datasource start closing ....
2023-04-27 17:03:46.616 INFO 54268 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} closing ...
2023-04-27 17:03:46.618 INFO 54268 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-1} closed
2023-04-27 17:03:46.619 INFO 54268 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-2} closing ...
2023-04-27 17:03:46.620 INFO 54268 --- [ main] com.alibaba.druid.pool.DruidDataSource : {dataSource-2} closed
2023-04-27 17:03:46.622 INFO 54268 --- [ main] c.b.d.d.DynamicRoutingDataSource : dynamic-datasource all closed success,bye
2023-04-27 17:03:46.886 INFO 54268 --- [ main] ConditionEvaluationReportLoggingListener :

Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2023-04-27 17:03:47.386 ERROR 54268 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter :


APPLICATION FAILED TO START


Description:

Parameter 0 of method mpjSpringContent in com.github.yulichang.autoconfigure.MybatisPlusJoinAutoConfiguration required a bean of type 'com.github.yulichang.autoconfigure.MybatisPlusJoinAutoConfiguration$MPJSpringContext' that could not be found.

Action:

Consider defining a bean of type 'com.github.yulichang.autoconfigure.MybatisPlusJoinAutoConfiguration$MPJSpringContext' in your configuration.

这个需要在配置类中额外配置什么吗?

DTO中的List创建与拼装

DTO & DO

dtoX {
  string a,
  int b
  List<dtoY> c
}
dtoY {
  string d
}

doX {
  string a,
  int b
}
doY {
  int b
  string d
}

查询

List<dtoX> list = mapperX.selectJoinList(dtoX.class,
  new MPLambdaWrapper<doX>()
    .selectAll(doX.class)
    .select(doY.d)
    .leftJoin(doY.class,doY::b,doX::b)
);

对于这样的查询,该如何设置dtoXList<dtoY> c呢?

wrapper.leftJoin,启用了逻辑删除,当右表为null时,生成的SQL不对

逻辑删除时,生成的WHERE条件如下:

FROM xxx t
         LEFT JOIN xxx t1 ON (t1.id = t.xxx_id)
WHERE t.DELETED = 0
  AND t1.DELETED = 0
  AND (t.id = ?)
ORDER BY t.id DESC
LIMIT 1;

当左表该列值为null时,返回值丢失了;
LEFT JOIN 应该保留null值;
正确的SQL应该如下:

FROM xxx t
         LEFT JOIN xxx t1 ON (t1.id = t.xxx_id)
WHERE t.DELETED = 0
  #AND t1.DELETED = 0
  AND (t.id = ?)
ORDER BY t.id DESC
LIMIT 1;

启动时报错:Parameter 'paramType_Gr8re1Ee' not found. Available parameters are [ew, param1]

环境:

springboot 版本2.6.6:

@Component
public class InitRunner implements CommandLineRunner {

}
<dependency>
	<groupId>com.baomidou</groupId>
	<artifactId>mybatis-plus-boot-starter</artifactId>
	<version>3.4.3</version>
</dependency>

<dependency>
	<groupId>com.github.yulichang</groupId>
	<artifactId>mybatis-plus-join</artifactId>
	<version>1.2.3</version>
</dependency>

启动时报错:

Caused by: org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.binding.BindingException: Parameter 'paramType_Gr8re1Ee' not found. Available parameters are [ew, param1]

MPJAbstractLambdaWrapper Column 空指针异常

当前使用版本(必填,否则不予处理)

1.2.4

该问题是如何引起的?(确定最新版也有问题再提!!!)

不同的实体数据库表,都有相同的查询条件,构造MPJLambdaWrapper时,期望不需要每个实体类都去处理一遍这些查询条件,相同的查询条件定义泛型方法来处理

重现步骤(如果有就写完整)

1,定义两个数据库实体,相同的字段放到基类Base

class Base {
  Long id;
  Long appId;
}

class A extends Base {
  String fieldA;
}

class B extends Base {
  String fieldB;
}

2,定义查询条件的泛型处理方法

protected <E extends Base> void handleAppId(MPJLambdaWrapper<E> qw, Long appId) {
        if (appId != null) {
            if (appId == -1L) {
                qw.eq(E::getAppId, -1L);
            } else {
                qw.and(t -> t.eq(E::getAppId, -1L)
                        .or().eq(E::getAppId, appId));
            }
        }
}

3,查询报错

报错信息

空指针异常,ColumnCache 字段缓存里面没有找到

nested exception is org.apache.ibatis.builder.BuilderException: Error evaluating expression 'ew.sqlSegment != null and ew.sqlSegment != '' and ew.nonEmptyOfWhere'. Cause: org.apache.ibatis.ognl.OgnlException: sqlSegment [java.lang.NullPointerException]

com.github.yulichang.wrapper.MPJAbstractLambdaWrapper, getCache(), 57
com.github.yulichang.wrapper.MPJAbstractLambdaWrapper, columnToString(), 47
com.github.yulichang.wrapper.MPJAbstractLambdaWrapper, columnToString(), 36

debug 可以看到缓存字段 columnMap 中只有 ClassA和ClassB,不会有个ClassBase,但是泛型Lambda传入的是ClassBase

升级到1.2.4 还是无法使用对应的plus-join下面的包

org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): com.xxx.mapper.IMailTemplateMapper.selectJoinList

启动时,我检查相关join包中的类都已经注入了
com.github.yulichang.config.InterceptorConfig中在sqlSessionFactoryList已经看到了mpjInterceptor

依赖jar包与程序分开打包的话(公司要求),查询时候,用了mpj的查询会报错,应该可以复现,mpj和mp都是最新版,demo地址 https://github.com/Ouyang-Yu/testMPJ/tree/master

报错信息显示,在MPJTableMapperHelper的
public static Class getEntity(Class clazz) {
return (Class)CACHE_REVERSE.get(clazz);
}
可能传入了一个null

打包结果如图
image

下面是打包的mvn配置,放在<build> <plugins> 里面

<!--            打包jar -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <!--不打包资源文件 -->
                    <excludes>
                        <exclude>*.**</exclude>
                        <exclude>*/*.xml</exclude>
                    </excludes>
                    <archive>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <!--MANIFEST.MF 中 Class-Path 加入前缀 -->
                            <classpathPrefix>lib/</classpathPrefix>
                            <!--jar包不包含唯一版本标识 -->
                            <useUniqueVersions>false</useUniqueVersions>
                            <!--指定入口类 -->
                            <mainClass>com.cawis.FbsDeviceServiceApplication</mainClass>
                        </manifest>
                        <manifestEntries>
                            <!--MANIFEST.MF 中 Class-Path 加入资源文件目录 -->
                            <Class-Path>./resources/</Class-Path>
                        </manifestEntries>
                    </archive>
                    <outputDirectory>${project.build.directory}</outputDirectory>
                </configuration>
            </plugin>

            <!--拷贝依赖 copy-dependencies -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>
                                ${project.build.directory}/lib/
                            </outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <!--拷贝资源文件 copy-resources -->
            <plugin>
                <artifactId>maven-resources-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-resources</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-resources</goal>
                        </goals>
                        <configuration>
                            <resources>
                                <resource>
                                    <directory>src/main/java</directory>
                                    <includes>
                                        <include>**/*.xml</include>
                                    </includes>
                                </resource>
                                <!--设置自己目录下的配置文件 -->
                                <resource>
                                    <!--下方resources的文件夹名字要和自己项目的文件夹名确认一致才行 很多人就是忽略了名字不一致 -->
                                    <directory>src/main/resources</directory>
                                    <includes>
                                        <include>**/*</include>
                                    </includes>
                                </resource>
                            </resources>
                            <outputDirectory>${project.build.directory}/resources</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

            <!--spring boot repackage,依赖 maven-jar-plugin 打包的jar包 重新打包成 spring boot
                的jar包 -->
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <!--重写包含依赖,包含不存在的依赖,jar里没有pom里的依赖 -->
                    <includes>
                        <include>
                            <groupId>null</groupId>
                            <artifactId>null</artifactId>
                        </include>
                    </includes>
                    <layout>ZIP</layout>
                    <!--使用外部配置文件,jar包里没有资源文件 -->
                    <addResources>true</addResources>
                    <outputDirectory>${project.build.directory}</outputDirectory>
                </configuration>
                <executions>
                    <execution>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                        <configuration>
                            <!--配置jar包特殊标识 配置后,保留原文件,生成新文件 *-run.jar -->
                            <!--配置jar包特殊标识 不配置,原文件命名为 *.jar.original,生成新文件 *.jar -->
                            <!--<classifier>run</classifier> -->
                        </configuration>
                    </execution>
                </executions>
            </plugin>
> h path [] threw exception [Request processing failed; nested exception is org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.exceptions.PersistenceException:
> ### Error querying database.  Cause: java.lang.NullPointerException
> ### Cause: java.lang.NullPointerException] with root cause
> java.lang.NullPointerException: null
        at java.util.concurrent.ConcurrentHashMap.get(ConcurrentHashMap.java:936) ~[na:1.8.0_362]
        at com.github.yulichang.mapper.MPJTableMapperHelper.getEntity(MPJTableMapperHelper.java:30) ~[mybatis-plus-join-core-1.4.4.1.jar:na]
        at com.github.yulichang.interceptor.MPJInterceptor.getMappedStatement(MPJInterceptor.java:89) ~[mybatis-plus-join-core-1.4.4.1.jar:na]
        at com.github.yulichang.interceptor.MPJInterceptor.intercept(MPJInterceptor.java:69) ~[mybatis-plus-join-core-1.4.4.1.jar:na]
        at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:62) ~[mybatis-3.5.10.jar:3.5.10]
        at com.sun.proxy.$Proxy212.query(Unknown Source) ~[na:na]
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) ~[mybatis-3.5.10.jar:3.5.10]
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) ~[mybatis-3.5.10.jar:3.5.10]
        at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) ~[mybatis-3.5.10.jar:3.5.10]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_362]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_362]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_362]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_362]
        at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) ~[mybatis-spring-2.0.7.jar:2.0.7]
        at com.sun.proxy.$Proxy120.selectList(Unknown Source) ~[na:na]
        at org.mybatis.spring.SqlSessionTemplate.selectList(SqlSessionTemplate.java:224) ~[mybatis-spring-2.0.7.jar:2.0.7]
        at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.executeForIPage(MybatisMapperMethod.java:121) ~[mybatis-plus-core-3.5.3.1.jar:3.5.3.1]
        at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.execute(MybatisMapperMethod.java:85) ~[mybatis-plus-core-3.5.3.1.jar:3.5.3.1]
        at com.baomidou.mybatisplus.core.override.MybatisMapperProxy$PlainMethodInvoker.invoke(MybatisMapperProxy.java:148) ~[mybatis-plus-core-3.5.3.1.jar:3.5.3.1]
        at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) ~[mybatis-plus-core-3.5.3.1.jar:3.5.3.1]
        at com.sun.proxy.$Proxy139.selectJoinPage(Unknown Source) ~[na:na]
        at com.cawis.service.impl.DeviceInfoServiceImpl.pageDeviceOnlineInfoVo(DeviceInfoServiceImpl.java:569) ~[classes!/:0.0.1-SNAPSHOT]
        at com.cawis.service.impl.DeviceInfoServiceImpl$$FastClassBySpringCGLIB$$1a18a5f4.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT]
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.23.jar:5.3.23]
        at org.springframework.aop.framework.CglibAopProxy.invokeMethod(CglibAopProxy.java:386) ~[spring-aop-5.3.23.jar:5.3.23]
        at org.springframework.aop.framework.CglibAopProxy.access$000(CglibAopProxy.java:85) ~[spring-aop-5.3.23.jar:5.3.23]
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:704) ~[spring-aop-5.3.23.jar:5.3.23]
        at com.cawis.service.impl.DeviceInfoServiceImpl$$EnhancerBySpringCGLIB$$23675066.pageDeviceOnlineInfoVo(<generated>) ~[classes!/:0.0.1-SNAPSHOT]
        at com.cawis.controller.DeviceController.onlineInfo(DeviceController.java:736) ~[classes!/:0.0.1-SNAPSHOT]
        at com.cawis.controller.DeviceController$$FastClassBySpringCGLIB$$a2554ec.invoke(<generated>) ~[classes!/:0.0.1-SNAPSHOT]
        at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) ~[spring-core-5.3.23.jar:5.3.23]
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:793) ~[spring-aop-5.3.23.jar:5.3.23]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) ~[spring-aop-5.3.23.jar:5.3.23]
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.23.jar:5.3.23]
        at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:64) ~[spring-aop-5.3.23.jar:5.3.23]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175) ~[spring-aop-5.3.23.jar:5.3.23]
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.23.jar:5.3.23]
        at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:57) ~[spring-aop-5.3.23.jar:5.3.23]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175) ~[spring-aop-5.3.23.jar:5.3.23]
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.23.jar:5.3.23]
        at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:58) ~[spring-aop-5.3.23.jar:5.3.23]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:175) ~[spring-aop-5.3.23.jar:5.3.23]
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.23.jar:5.3.23]
        at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:97) ~[spring-aop-5.3.23.jar:5.3.23]
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.3.23.jar:5.3.23]
        at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:763) ~[spring-aop-5.3.23.jar:5.3.23]
        at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:708) ~[spring-aop-5.3.23.jar:5.3.23]
        at com.cawis.controller.DeviceController$$EnhancerBySpringCGLIB$$75afecec.onlineInfo(<generated>) ~[classes!/:0.0.1-SNAPSHOT]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_362]
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_362]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_362]
        at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_362]
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205) ~[spring-web-5.3.23.jar:5.3.23]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150) ~[spring-web-5.3.23.jar:5.3.23]
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117) ~[spring-webmvc-5.3.23.jar:5.3.23]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895) ~[spring-webmvc-5.3.23.jar:5.3.23]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808) ~[spring-webmvc-5.3.23.jar:5.3.23]
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.3.23.jar:5.3.23]
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1071) ~[spring-webmvc-5.3.23.jar:5.3.23]
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:964) ~[spring-webmvc-5.3.23.jar:5.3.23]
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.23.jar:5.3.23]
        at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:909) ~[spring-webmvc-5.3.23.jar:5.3.23]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:696) ~[tomcat-embed-core-9.0.68.jar:4.0.FR]
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.23.jar:5.3.23]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:779) ~[tomcat-embed-core-9.0.68.jar:4.0.FR]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.68.jar:9.0.68]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:142) ~[spring-session-core-2.6.3.jar:2.6.3]
        at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:82) ~[spring-session-core-2.6.3.jar:2.6.3]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.3.23.jar:5.3.23]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117) ~[spring-web-5.3.23.jar:5.3.23]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:197) ~[tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:97) [tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) [tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:135) [tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) [tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:78) [tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:360) [tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:399) [tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) [tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:893) [tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1789) [tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191) [tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659) [tomcat-embed-core-9.0.68.jar:9.0.68]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-9.0.68.jar:9.0.68]
        at java.lang.Thread.run(Thread.java:750) [na:1.8.0_362]

如何join 多个条件

SELECT A.id
FROM A left join B
on A.id=B.a_id and A.xx=12 and B.id<100

如何实现这样的查询?
我需要查询记录数和数据

连接查询时的Bug

使用 selectJoinPage() 方法进行分页查询时,查询总记录条数时,没有进行表连接。

多个条件构造器使用,报空指针问题

连表查询时,多个条件构造器连续使用condition参数来控制SQL是否拼接,当condition参数传入 对布尔包装类型参数的null判断 会出现空指针异常问题,还有LocalDateTime数组 对象 null值判断 ,其他类型暂未出现

引入之后,原有的方法报错,大佬帮看看

"程序错误|doDispatch(DispatcherServlet.java:1053)|Handler dispatch failed; nested exception is java.lang.AbstractMethodError: com.github.yulichang.interceptor.MPJInterceptor.plugin(Ljava/lang/Object;)Ljava/lang/Object;"

想问一下如下一个三表查询的场景如何构造返回DTO才能接收正确

有如下三张表且关系如下:
Teacher <----一对多----> User<----多对一----->Class
现在想要知道某个teacherId老师下所有学生的信息以及各个学生的班级名称,我使用如下wrapper
MPJLambdaWrapper wrapper = new MPJLambdaWrapper()
.selectAll(Teacher.class)
.select(Class::getClassName)
.selectCollection(User.class,ResDTO::getUserList)
.leftJoin(User.class, User::getUserId, Teacher::getUserId)
.leftJoin(Class.class,Class::getClassId,SealAuditTask::getClassId)
.eq(Teacher::getTeacherId,teacherId);
teacherMapper.selectJoinOne(ResDTO.class,wrapper);
这样子的话,通过日志看到SQL语句确实能够正确执行,且班级名称ClassName也返回了,但是由于不知道如何定义ResDTO所以返回的ResDTO对象中并没有这个属性,怎么加都没法注入,希望看看。
目前的ResDTO如下:
@DaTa
public class ResDTO {
private Integer teacherId;
private List users;
}

使用selectJoinPage进行查询时,分页结果不对问题

只使用了selectAll和selectAssociation以及在selectAssociation中多次使用association,且分页时传入的一页展示10条,但结果返回的数据只有两条,结果超出实际数据条数。实际通过生成出的sql执行发现只有10条数据

MPJLambdaWrapper<CoursescheduleTimesDO> lqw = new MPJLambdaWrapper<CoursescheduleTimesDO>()
            .selectAll(CoursescheduleTimesDO.class)
    .selectAssociation(CoursescheduleBasicinfoDO.class, CoursescheduleTimesRespVO::getBasicinfoIdObj,map->map
            .result(CoursescheduleBasicinfoDO::getCreateTime)
            .result(CoursescheduleBasicinfoDO::getCourseinfoId)
            .result(CoursescheduleBasicinfoDO::getTerminfoId)
            .result(CoursescheduleBasicinfoDO::getTchinfoId)
            .result(CoursescheduleBasicinfoDO::getClassinfoId)
            .result(CoursescheduleBasicinfoDO::getIsOptional)
            .result(CoursescheduleBasicinfoDO::getIsPublic)
                    .association(ClasssysClassinfoDO.class, CoursescheduleBasicinfoRespVO::getClassinfoIdObj)
                    .association(CoursesysCourseinfoDO.class, CoursescheduleBasicinfoRespVO::getCourseinfoIdObj)
                    .association(TermsysTerminfoDO.class,CoursescheduleBasicinfoRespVO::getTerminfoIdObj)
                    .association(TchinfoInfoDO.class,CoursescheduleBasicinfoRespVO::getTchinfoIdObj)
    )
    .selectAssociation(CourseadjustAdjustinfoDO.class, CoursescheduleTimesRespVO::getAdjustinfoIdObj,map->map
            .result(CourseadjustAdjustinfoDO::getCreateTime)
            .result(CourseadjustAdjustinfoDO::getTimesId)
            .result(CourseadjustAdjustinfoDO::getProcessInstanceId)
            .result(CourseadjustAdjustinfoDO::getResult)
            .result(CourseadjustAdjustinfoDO::getNewWeekNum)
            .result(CourseadjustAdjustinfoDO::getNewStartTimes)
            .result(CourseadjustAdjustinfoDO::getNewEndTimes)
            .result(CourseadjustAdjustinfoDO::getNewWeek)
    )
            .between(reqVO.getCreateTime() != null, CoursescheduleTimesDO::getCreateTime,
            ArrayUtil.get(reqVO.getCreateTime(), 0),
            ArrayUtil.get(reqVO.getCreateTime(), 1)
            )
                .in(!classinfoIds.isEmpty(),ClasssysClassinfoDO::getId,classinfoIds)
                .eq(reqVO.getWeekNum() != null,CoursescheduleTimesDO::getWeekNum, reqVO.getWeekNum())
                .eq(reqVO.getStartTimes() != null,CoursescheduleTimesDO::getStartTimes, reqVO.getStartTimes())
                .eq(reqVO.getEndTimes() != null,CoursescheduleTimesDO::getEndTimes, reqVO.getEndTimes())
                .eq(reqVO.getWeek() != null,CoursescheduleTimesDO::getWeek, reqVO.getWeek())
                .eq(reqVO.getBasicinfoId() != null,CoursescheduleTimesDO::getBasicinfoId, reqVO.getBasicinfoId())
                .eq(reqVO.getAdjustinfoId() != null,CoursescheduleTimesDO::getAdjustinfoId, reqVO.getAdjustinfoId())
    .leftJoin(
        CoursescheduleBasicinfoDO.class,
        CoursescheduleBasicinfoDO::getId,
        CoursescheduleTimesDO::getBasicinfoId
    )
    .leftJoin(
            ClasssysClassinfoDO.class,
            ClasssysClassinfoDO::getId,
            CoursescheduleBasicinfoDO::getClassinfoId
    )
    .leftJoin(
        CourseadjustAdjustinfoDO.class,
        CourseadjustAdjustinfoDO::getId,
        CoursescheduleTimesDO::getAdjustinfoId
    )
    .leftJoin(
        CoursesysCourseinfoDO.class,
        CoursesysCourseinfoDO::getId,
        CoursescheduleBasicinfoDO::getCourseinfoId
    )
    .leftJoin(
        StuinfoBasicDO.class,
        StuinfoBasicDO::getClassinfoId,
        ClasssysClassinfoDO::getId
    )
    .leftJoin(
        TermsysTerminfoDO.class,
        TermsysTerminfoDO::getId,
        CoursescheduleBasicinfoDO::getTerminfoId
    )
    .leftJoin(
        TchinfoInfoDO.class,
        TchinfoInfoDO::getId,
        CoursescheduleBasicinfoDO::getTchinfoId
    )
            .orderByDesc(CoursescheduleTimesDO::getId);

        Page<CoursescheduleTimesRespVO> res = coursescheduleTimesMapper.selectJoinPage(MyBatisUtils.buildPage(reqVO), CoursescheduleTimesRespVO.class, lqw);

通过debug形式打断点获取的数据:
image

通过连表查执行的SQL去数据库中 跑一遍结果如下:
image

似乎不支持对数据库中不存在数据表的实体类进行映射

我有这样的需求:
我的数据库中有character表、character_skill表
character表中主键为id
character_skill表是一个中间表,其中除了character_id和skill_id作为双主键外,还有几个字段例如grow_value,profession_value等,
代表技能的成长值和职业点值,这些字段是每个角色的每个技能独有的,所以我将这些字段直接放到了character和skill关联的中间表中,
而由于需要在character实体类传给前端的时候有一个List ownSkills字段存放每个角色拥有技能的一些独有值(不想将character_id传过去),所以我在后端增加了一个OwnSkill实体类去拿中间表的这几个grow_value、profession_value等字段
我的OwnSkill并没有character_id这个字段,他只放每个角色拥有的每个技能的独有值
2023-05-17_213929
这个OwnSkill实体类作为Character类的一个虚拟字段(即character数据表中不存在这个字段)
2023-05-17_213517
使用关联查询
由于OwnSkill这个实体类并没有在数据库中存在,无法直接进行映射,请问使用MPJLambdaWrapper的leftJoin是否有办法实现这种间接的映射,比如我想通过leftJoin将character_skill这个中间表需要用到的字段数据取出来然后赋值给Character的OwnSkills字段
就例如我使用xml实现的
2023-05-17_214559
请问目前使用mpj能实现这种需求吗,我看了文档似乎没看到有这种将字段给不同于表映射的实体类的地方,请多指教

Kotlin支持

对于Kotlin类型的Entity,好像没法使用

val dList = deviceService.baseMapper.selectJoinList(
            DeviceInfo::class.java, MPJLambdaWrapper<Device>()
                .selectAll(DeviceInfo::class.java)
                .leftJoin(DeviceInfo::class.java, DeviceInfo::deviceNo, Device::deviceNo)
                .eq(Device::ownerId, owner.id)
        )

error

该方法仅能传入 lambda 表达式产生的合成类
com.baomidou.mybatisplus.core.exceptions.MybatisPlusException: 该方法仅能传入 lambda 表达式产生的合成类
	at com.baomidou.mybatisplus.core.toolkit.ExceptionUtils.mpe(ExceptionUtils.java:49)
	at com.baomidou.mybatisplus.core.toolkit.support.SerializedLambda.resolve(SerializedLambda.java:56)
	at com.baomidou.mybatisplus.core.toolkit.LambdaUtils.lambda$resolve$0(LambdaUtils.java:64)
	at java.util.Optional.orElseGet(Optional.java:267)
	at com.baomidou.mybatisplus.core.toolkit.LambdaUtils.resolve(LambdaUtils.java:63)
	at com.github.yulichang.toolkit.LambdaUtils.getColumn(LambdaUtils.java:29)
	at com.github.yulichang.wrapper.MPJLambdaWrapper.join(MPJLambdaWrapper.java:210)
	at com.github.yulichang.wrapper.MPJLambdaWrapper.join(MPJLambdaWrapper.java:29)
	at com.github.yulichang.wrapper.interfaces.LambdaJoin.leftJoin(LambdaJoin.java:17)
	at com.github.yulichang.wrapper.interfaces.LambdaJoin.leftJoin(LambdaJoin.java:13)
	at DeviceInfoController.list(DeviceInfoController.kt:46)

多个mapper继承MPJBaseMapper出现重复注入z

org.springframework.context.annotation.ConflictingBeanDefinitionException: Annotation-specified bean name '' for bean class [] conflicts with existing, non-compatible bean definition of same name and class [***]
at org.springframework.context.annotation.ClassPathBeanDefinitionScanner.checkCandidate(ClassPathBeanDefinitionScanner.java:348)

debug注入过程,重复的beanName 注入了两遍

`and`子查询时,无法指定表别名

查询语句:

wrapper.and(w -> {
    for(Consumer<MPJLambdaWrapper<Example>> executor : executors) {
        w.or();
        executor.accept(w);
    }
});

此处的 w 无法定义别名(hasAliasfalse),导致对主表使用的默认的 t 别名

多拦截器执行顺序问题

问题描述:mybatis配置了三个拦截器:多租户,分页拦截器和MPJInterceptor拦截;
在项目启动时执行的sql语句,如在ApplicationRunner或者CommandLineRunner执行的初始化方法,会提示binding异常,找不到MPJ内部变量paramType_Gr8re1Ee;
在spring-boot2.0中ApplicationRunner或者CommandLineRunner执行在ApplicationStartedEvent之后执行,在ApplicationReadyEvent之前执行,所以InterceptorConfig中监听的ApplicationReadyEvent事件来更改拦截器顺序对Runner执行的sql无效

MPJLambdaWrapper postgresql字段名大写,Like部分无法拼接出TableField 配置的引号

样例代码

pojo

@TableName("\"ST_STBPRP_B\"")
@EqualsAndHashCode(callSuper = true)
public class ST_STBPRP_B extends GeometryBaseEntity implements Serializable {

    /**
     * 测站名
     */
    @TableField("\"STNM\"")
    private String stnm;

}

service

var like = new MPJLambdaWrapper<ST_STBPRP_B>()
                .select(ST_STBPRP_B::getStnm)
                .like(ST_STBPRP_B::getStnm, stnm);
mapper.selectOne(like)

结果

### SQL: SELECT    t."STNM"  FROM "ST_STBPRP_B"   t          WHERE   (t.STNM LIKE ?)
### Cause: org.postgresql.util.PSQLException: ERROR: column t.stnm does not exist

从拼接出来的sql可以看到like条件STNM并没有按照 @TableField中的value一致,但是在select中是正确的

lambajoin同一张表问题

select * from user t inner user t2 on t.id = t1.id
正常写会解析成t.id = t.id, 使用lambajoin能否强制设置第一个参数为前一张表,第二个参数为后一张表

多个条件构造器使用,报空指针问题

连表查询时,多个条件构造器连续使用condition参数来控制SQL是否拼接,当condition参数传入 对布尔包装类型参数的null判断 会出现空指针异常问题,还有LocalDateTime数组 对象 null值判断 ,其他类型暂未出现

关键代码如图:
image

选中的参数 都是默认值,走到选中参数对应的条件构造器时就会报空指针问题 这种情况

什么时候支持kotlin

这样使用kotlin,发现会报错
override fun findByJoinLimit(): List? {
val wrapper: MPJLambdaWrapper = MPJLambdaWrapper()
.selectAll(ProductDataEntity::class.java)
// .selectAll(ProductInfoEntity::class.java)
.leftJoin(ProductInfoEntity::class.java, ProductInfoEntity::sku, ProductDataEntity::sku)
return productDataJoinMapper.selectJoinList(ProductDataJoinEntity::class.java, wrapper)
}

Caused by: org.apache.ibatis.reflection.ReflectionException: Error parsing property name 'findByJoinLimit$lambda$0'. Didn't start with 'is', 'get' or 'set'.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.