使用Mapper方式进行联表查询

有些业务场景需要查询两张表的数据,这时候就需要用到联表查询。下面将介绍两种方式进行联表查询。

场景:A模型页面,查询条件中包含B模型字段

模型A

@Model.model(YesOne.MODEL_MODEL)
@Model(displayName = "YesOne", summary = "YesOne")
public class YesOne extends IdModel {

    public static final String MODEL_MODEL = "top.YesOne";

    @Field.Integer
    @Field(displayName = "YesId")
    private Long yesId;

    @Field.String
    @Field(displayName = "名字")
    private String name;

    @Field.String
    @Field(displayName = "科目名字")
    private String professionalName;

    @Field(displayName = "关联YesTwo")
    @Field.many2one
    @Field.Relation(relationFields = {"yesId"},referenceFields = {"id"})
    private YesTwo yesTwo;

}

模型B

@Model.model(YesTwo.MODEL_MODEL)
@Model(displayName = "YesTwo", summary = "YesTwo")
public class YesTwo extends IdModel {

    public static final String MODEL_MODEL = "top.YesTwo";

    @Field.Integer
    @Field(displayName = "科目id")
    private Long professionalId;

    @Field.String
    @Field(displayName = "科目名字")
    private String professionalName;

}

1. 使用in的方式查询

通过B模型的查询条件查询出符合条件的所有数据ID,再根据这个ID去A模型里面查询出所需的数据。

    @Function.Advanced(displayName = "查询列表", type = FunctionTypeEnum.QUERY, category = FunctionCategoryEnum.QUERY_PAGE, managed = true)
    @Function(openLevel = {FunctionOpenEnum.LOCAL, FunctionOpenEnum.REMOTE, FunctionOpenEnum.API})
    public Pagination<YesOne> queryPage(Pagination<YesOne> page, IWrapper<YesOne> queryWrapper) {

        String professionalName = (String) queryWrapper.getQueryData().get("professionalName");
        if (StringUtils.isNotBlank(professionalName)) {
            List<Long> yesTwoId = new YesTwo().queryList(Pops.<YesTwo>lambdaQuery()
                            .from(YesTwo.MODEL_MODEL)
                            .eq(YesTwo::getProfessionalName, professionalName))
                    .stream().map(YesTwo::getId)
                    .collect(Collectors.toList());
            LambdaQueryWrapper<YesOne> wq = Pops.<YesOne>lambdaQuery().from(YesOne.MODEL_MODEL);
            if (CollectionUtils.isNotEmpty(yesTwoId)) {
                wq.in(YesOne::getYesId, yesTwoId);
            }
            return new YesOne().queryPage(page, wq);
        }
        return new YesOne().queryPage(page, queryWrapper);
    }

2. 使用mapper的方式查询

利用sql的方式去直接查询出结果。使用联表查询的方式查询

    @Autowired
    private YesOneQueryMapper yesOneQueryMapper;

    @Function.Advanced(displayName = "查询列表", type = FunctionTypeEnum.QUERY, category = FunctionCategoryEnum.QUERY_PAGE, managed = true)
    @Function(openLevel = {FunctionOpenEnum.LOCAL, FunctionOpenEnum.REMOTE, FunctionOpenEnum.API})
    public Pagination<YesOne> queryPage(Pagination<YesOne> page, IWrapper<YesOne> queryWrapper) {

        try (DsHintApi dsHint = DsHintApi.model(YesOne.MODEL_MODEL)) {
            String professionalName = (String) queryWrapper.getQueryData().get("professionalName");
            String yesOneTable = PamirsSession.getContext().getModelCache().get(YesOne.MODEL_MODEL).getTable();
            String yesTwoTable = PamirsSession.getContext().getModelCache().get(YesTwo.MODEL_MODEL).getTable();
            StringBuffer where = new StringBuffer().append("a.is_deleted = 0").append(CharacterConstants.SEPARATOR_BLANK)
                    .append(SqlConstants.AND).append(CharacterConstants.SEPARATOR_BLANK)
                    .append("b.is_deleted=0").append(CharacterConstants.SEPARATOR_BLANK);
            if (StringUtils.isNotBlank(professionalName)) {
                where.append(SqlConstants.AND).append(CharacterConstants.SEPARATOR_BLANK).append("b.").
                        append(PStringUtils.fieldName2Column(LambdaUtil.fetchFieldName(YesOne::getProfessionalName))).append(CharacterConstants.SEPARATOR_BLANK).
                        append(SqlConstants.EQ).append(professionalName);
            }
            StringBuffer limit = new StringBuffer().append(page.getStart() + " , " + page.getSize());
            List<YesOne> yesOnes = yesOneQueryMapper.unionTableQuery(yesOneTable, yesTwoTable, where.toString(), limit.toString());
            Long total = yesOneQueryMapper.queryTotal(yesOneTable, yesTwoTable, where.toString());
            page.setTotalElements(total);
            page.setContent(yesOnes);
        }
        return page;
    }

接口

package pro.shushi.pamirs.top.core.service;

import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
import pro.shushi.pamirs.top.api.model.YesOne;

import java.util.List;

@Mapper
public interface YesOneQueryMapper {

    @Select("<script>"
            + "SELECT "
            + "a.id , "
            + "a.name, "
            + "b.professional_name as professionalName "
            + "FROM ${yesOne} a "
            + "INNER JOIN ${yesTwo} b ON a.yes_id = b.id "
            + "<if test='whereConditions != null'>"
            + "where (${whereConditions}) "
            + "</if>"
            + "ORDER BY a.id ASC "
            + "<if test='limitConditions != null'>"
            + "LIMIT ${limitConditions} "
            + "</if>"
            + "</script>")
    List<YesOne> unionTableQuery(@Param("yesOne") String yesOne, @Param("yesTwo") String yesTwo, @Param("whereConditions") String whereConditions, @Param("limitConditions") String limitConditions);

    @Select("<script>"
            + "SELECT count(a.id )"
            + "FROM ${yesOne} a "
            + "INNER JOIN ${yesTwo} b ON a.yes_id = b.id "
            + "<if test='whereConditions != null'>"
            + "where (${whereConditions}) "
            + "</if>"
            + "</script>")
    Long queryTotal(@Param("yesOne") String yesOne, @Param("yesTwo") String yesTwo, @Param("whereConditions") String whereConditions);

}

Oinone社区 作者:yexiu原创文章,如若转载,请注明出处:https://doc.oinone.top/kai-fa-shi-jian/17950.html

访问Oinone官网:https://www.oinone.top获取数式Oinone低代码应用平台体验

Like (0)
yexiu's avataryexiu数式员工
Previous 2024年9月27日 am11:20
Next 2024年9月29日 pm8:56

相关推荐

  • Oinone构建分布式项目一些注意点

    1. Oinone如何支持构建分布式项目 参考文档:https://doc.oinone.top/kai-fa-shi-jian/5572.html 2. Oinone远程服务发布范围 泛化服务范围,可选值:module、namespacemodule:按模块维度发布远程服务namespace:按Fun的namespace维度发布远程服务默认按module维度发布服务 pamirs: distribution: service: #serviceScope: 可选值namespace、module serviceScope: module 3.关闭Dubbo服务注册元数据上报日志 logging: level: root: info pro.shushi.pamirs.framework.connectors.data.mapper.PamirsMapper: error pro.shushi.pamirs.framework.connectors.data.mapper.GenericMapper: error # mybatis sql日志 RocketmqClient: error org.apache.dubbo.registry.zookeeper.ZookeeperRegistry: error org.apache.dubbo.registry.integration.RegistryDirectory: error org.apache.dubbo.config.ServiceConfig: error com.alibaba.nacos.client.naming: error org.apache.dubbo.registry.nacos.NacosRegistry: error org.apache.dubbo.registry.support.AbstractRegistryFactory: error org.apache.dubbo.registry.integration.RegistryProtocol: error org.apache.dubbo.registry.client.metadata.store.RemoteMetadataServiceImpl: off org.apache.dubbo.metadata.store.zookeeper.ZookeeperMetadataReport: off org.apache.dubbo.metadata.store.nacos.NacosMetadataReport: off 4.Naocs配置列表出现多余配置 dubbo 集成 nacos注册中心,会出现多余的配置,详细参考:配置列表会自动创建很多无关的配置: https://github.com/apache/dubbo/issues/6645配置列表出现多余的配置:https://github.com/alibaba/nacos/issues/8843 按照下面的配置可以将其关闭(📢主要是这三项配置use-as-config-center, use-as-metadata-center,metadata-report.failfast),已生成的配置需要手动删除掉。 dubbo: application: name: pamirs-demo version: 1.0.0 metadata-type: local registry: id: pamirs-demo-registry address: nacos://192.168.0.129:8848 username: nacos password: nacos # dubbo使用nacos的注册中心往配置中心写入配置关闭配置 use-as-metadata-center: false use-as-config-center: false config-center: address: nacos://192.168.0.129:8848 username: nacos password: nacos metadata-report: failfast: false # 关闭错误上报的功能 address: nacos://192.168.0.129:8848 username: nacos password: nacos protocol: name: dubbo port: -1 serialization: pamirs scan: base-packages: pro.shushi cloud: subscribed-services:

    2024年2月1日
    1.9K10
  • Oinone登录扩展:对接SSO(适应于4.7.8之前的版本)

    适配版本 4.7.8之前的版本 概述 在企业内部,对于已有一套完整的登录系统(SSO)的情况下,通常会要求把所有的系统都对接到SSO中;本文主要讲解用Oinone开发的项目对接SSO的具体实现。 对接步骤 1、项目自定义实现UserCookieLogin,可参考示例说明: pro.shushi.pamirs.user.api.login.UserCookieLoginFree 2、对接SSO示例 对接流程说明: 1)【必须】从请求头Header或者Query中获取到token; 2)【必须】去SSO服务端验证token的有效性; 3)【可选】根据token去服务端获取用户信息;如果token可以直接反解析出用户信息,则该步骤忽略; 4)【可选】根据实际情况用户信息是否进行DB的存储; 5)【必须】验证token有效后,生成Session和Cookie(即token换cookie); 注意超时时间需要 <= SSO服务端token失效时间。 package pro.shushi.pamirs.demo.core.sso; import com.alibaba.fastjson.JSON; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.core.annotation.Order; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import pro.shushi.pamirs.demo.core.sso.constant.HttpConstant; import pro.shushi.pamirs.demo.core.sso.constant.SSOConstant; import pro.shushi.pamirs.demo.core.sso.constant.SessionUserTypeEnum; import pro.shushi.pamirs.demo.core.sso.model.ApiCommonTransient; import pro.shushi.pamirs.demo.core.sso.utils.AuthenticateUtils; import pro.shushi.pamirs.demo.core.sso.model.PermissionInfoResp; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.api.dto.model.PamirsUserDTO; import pro.shushi.pamirs.meta.api.dto.protocol.PamirsRequestVariables; import pro.shushi.pamirs.meta.api.session.PamirsSession; import pro.shushi.pamirs.meta.common.exception.PamirsException; import pro.shushi.pamirs.meta.common.spring.BeanDefinitionUtils; import pro.shushi.pamirs.meta.common.util.UUIDUtil; import pro.shushi.pamirs.resource.api.enmu.UserSignUpType; import pro.shushi.pamirs.user.api.cache.UserCache; import pro.shushi.pamirs.user.api.constants.UserConstant; import pro.shushi.pamirs.user.api.enmu.UserExpEnumerate; import pro.shushi.pamirs.user.api.enmu.UserLoginTypeEnum; import pro.shushi.pamirs.user.api.login.IUserLoginChecker; import pro.shushi.pamirs.user.api.login.UserCookieLogin; import pro.shushi.pamirs.user.api.login.UserCookieLoginSimple; import pro.shushi.pamirs.user.api.model.PamirsUser; import pro.shushi.pamirs.user.api.model.tmodel.PamirsUserTransient; import pro.shushi.pamirs.user.api.service.UserService; import pro.shushi.pamirs.user.api.utils.CookieUtil; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.concurrent.TimeUnit; /** * * @author wangxian * * 完全自定义login的过程 * 需要实现登陆部分login 以及拦截部分fetchUserIdByReq * 如果fetchUserIdByReq返回值为null的时候 将会被拦截 */ @Slf4j @Order(0) @Component public class DemoUserSSOCookieLogin extends UserCookieLogin<PamirsUser> { //刷新令牌 private static String REFRESH_TOKEN = "refreshToken"; //系统id private static String CLIENT_ID = "client-id"; //访问令牌 private static String AUTHORIZATION = "Authorization"; private IUserLoginChecker checker; @Autowired private UserService userService; @Autowired private RedisTemplate<String, String> redisTemplate; @Override public String createSessionId(HttpServletRequest request, PamirsUser idModel) { return UUIDUtil.getUUIDNumberString(); } @Override public String type() { return UserLoginTypeEnum.COOKIE.value(); } @Override public PamirsUser resolveAndVerification(PamirsUserTransient user) { if (checker == null) { checker =…

    2023年11月24日
    2.0K00
  • 问题排查调试工具使用手册

    当前端发起对应用的访问时,如果出现错误,那么我们可以通过以下方式进行简易排查,如果排查不出来,则也可以把排查工具给出的信息发送给Oinone官方售后进行进一步分析。本文将通过模拟异常信息,来介绍排查工具,提供了哪些辅助信息帮我们来快速定位问题。 排查工具基础介绍 通过前端页面的 /debug 路由路径访问调试工具的页面,假设我们的前端页面访问地址为http://localhost:6800,那么我们的排查工具请求路径就是 http://localhost:6800/debug排查工具可以帮我们排查前端页面元数据异常和后端接口的异常 排查前端页面元数据 将问题页面浏览器地址栏内 page 后的部分复制到调试工具的 debug 路由后重新发起请求,如图可以看到调试工具展示的信息,可以根据这些信息排查问题。 排查后端接口 后端接口出现问题后,打开(在原页面)浏览器的调试工具,切换到“网络”的标签页,在左侧的历史请求列表中找到需要调试的请求,右键会弹出菜单,点击菜单中的 “复制”,再次展开该菜单,点击二级菜单中的“以 fetch 格式复制”,这样可以复制到调试所需要的信息 2.复制调试信息到“接口调试”标签页内的文本框内,点击“发起请求”按钮获取调试结果 我们可以看到页面展示了该接口的各种调试信息,我们可以据此排查问题。 场景化的排查思路 业务代码中存在代码bug 报错后发起调试请求,我们可以看到,调试工具直接给出了异常抛出的具体代码所在位置,此时再切换到“全部堆栈”下,可以看到是业务类的233行导致的空指针异常,查看代码后分析可得是data.getName().eqauls方法在调用前未做条件判断补全该判断后代码可以正常执行 业务代码中没有直接的错误,异常在平台代码中抛出 报错后发起调试请求可以看到异常不在业务代码内再切换到“全部堆栈”,可以看到具体异常信息,提示core_demo_item表出现了重复的主键,该表是DemoItem模型的我们还可以切换到“sql调试”的标签页,可以看到出错的具体sql语句经过分析可以得知是240行的data.create()�重复创建数据导致的。 三、排查工具无法定位怎么办 当我们通过排查工具还是没有定位到问题的时候,可以通过调试页面的“下载全部调试数据”和“下载调试数据”按钮将调试信息的数据发送给官方售后人员帮助我们定位排查问题。 点击页面最顶部的“下载全部调试数据”按钮,可以下载页面调试数据和接口调试数据点击“调试接口”标签页内的“下载调试数据”按钮,可以下载接口调试数据 四、排查工具细节

    2024年5月21日
    2.8K00
  • Oinone协同开发使用手册

    概述 Oinone平台为开发人员提供了本地环境 – 测试环境之间的协同开发模式,可以使得开发人员在本地环境中设计的模型、函数等元数据实时被测试环境使用并设计。开发人员开发完成对应页面和功能后,可以部署至测试环境直接进行测试。 本篇文章将详细介绍协同开发模式在实际开发中的应用及相关内容。 名词解释 本地环境: 开发人员的本地启动环境 测试环境: 在测试服务器上部署的业务测试环境,业务工程服务和设计器服务共用中间件 业务工程服务:在测试服务器上部署的业务工程 设计器服务: 在测试服务器上部署的设计器镜像 一套环境:以测试环境为例,业务工程服务和设计器服务共同组成一套环境 生产环境: 在生产服务器上部署的业务生产环境 环境准备 部署了一个可用的设计器服务,并能正常访问。(需参照下文启动设计器环境内容进行相应修改) 准备一个用于开发的java工程。 准备一个用于部署测试环境的服务器。 协同参数介绍 用于测试环境的参数 -PmetaProtected=${value} 启用元数据保护,只有配置相同启动参数的服务才允许对元数据进行更新。通常该命令用于设计器服务和业务工程服务,并且两个环境需使用相同的元数据保护标记(value)进行启动。本地环境不使用该命令,以防止本地环境在协同开发时意外修改测试环境元数据,导致元数据混乱。 用法 java -jar boot.jar -PmetaProtected=pamirs 用于本地环境的配置 使用命令配置ownSign(推荐) java -jar boot.jar –pamirs.distribution.session.ownSign=demo 使用yaml配置ownSign pamirs: distribution: session: allMetaRefresh: false # 启用元数据全量刷新(备用配置,如遇元数据错误或混乱,启用该配置可进行恢复,使用一次后关闭即可) ownSign: demo # 协同开发元数据隔离标记,用于区分不同开发人员的本地环境,其他环境不允许使用 启动设计器环境 docker-run启动 -e PROGRAM_ARGS=-PmetaProtected=pamirs docker-compose启动 services: backend: container_name: designer-backend image: harbor.oinone.top/oinone/designer-backend-v5.0 restart: always environment: # 指定spring.profiles.active ARG_ENV: dev # 指定-Plifecycle ARG_LIFECYCLE: INSTALL # jvm参数 JVM_OPTIONS: "" # 程序参数 PROGRAM_ARGS: "-PmetaProtected=pamirs" PS: java [JVM_OPTIONS?] -jar boot.jar [PROGRAM_ARGS?] 开发流程示例图 具体使用步骤详见协同开发支持

    2024年7月24日
    2.6K00
  • 如何加密gql请求内容

    介绍 在一些对安全等级要求比较高的场景,oinone提供了扩展前端加密请求内容,后端解密请求内容的能力,该方案要求前后端的加解密方案统一。 后端 1. 继承平台的RequestController新增一个请求类,在里面处理加密逻辑 package pro.shushi.pamirs.demo.core.controller; import org.apache.commons.lang3.StringUtils; import org.springframework.web.bind.annotation.*; import pro.shushi.pamirs.framework.gateways.graph.java.RequestController; import pro.shushi.pamirs.meta.annotation.fun.extern.Slf4j; import pro.shushi.pamirs.meta.api.dto.protocol.PamirsClientRequestParam; import pro.shushi.pamirs.user.api.utils.AES256Utils; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.util.HashMap; import java.util.List; import java.util.Map; @RestController @Slf4j public class DemoRequestController extends RequestController { @SuppressWarnings("unused") @RequestMapping( value = "/pamirs/{moduleName:^[a-zA-Z][a-zA-Z0-9_]+[a-zA-Z0-9]$}", method = RequestMethod.POST ) public String pamirsPost(@PathVariable("moduleName") String moduleName, @RequestBody PamirsClientRequestParam gql, HttpServletRequest request, HttpServletResponse response) { decrypt(gql); return super.pamirsPost(moduleName, gql, request, response); } @SuppressWarnings("unused") @RequestMapping( value = "/pamirs/{moduleName:^[a-zA-Z][a-zA-Z0-9_]+[a-zA-Z0-9]$}/batch", method = RequestMethod.POST ) public String pamirsBatch(@PathVariable("moduleName") String moduleName, @RequestBody List<PamirsClientRequestParam> gqls, HttpServletRequest request, HttpServletResponse response) { for (PamirsClientRequestParam gql : gqls) { decrypt(gql); } return super.pamirsBatch(moduleName, gqls, request, response); } private static final String GQL_VAR = "gql"; private void decrypt(PamirsClientRequestParam gql) { Map<String, Object> variables = null != gql.getVariables() ? gql.getVariables() : new HashMap<>(); String encodeStr = (String) variables.get(GQL_VAR); if (StringUtils.isNotBlank(encodeStr)) { variables.put(GQL_VAR, null); // TODO 此处的加密方法可以换为其他算法 String gqlQuery = AES256Utils.decrypt(encodeStr); gql.setQuery(gqlQuery); } } } 2.boot工程的启动类排除掉平台默认的RequestController类 @ComponentScan( excludeFilters = { // 该注解排除平台的RequestController类 @ComponentScan.Filter( type = FilterType.REGEX, pattern = "pro.shushi.pamirs.framework.gateways.graph.java.RequestController" ) }) public class DemoApplication { } 以下为实际项目中的启动类示例 package pro.shushi.pamirs.demo.boot; import org.apache.ibatis.annotations.Mapper; import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.WebApplicationType; import org.springframework.boot.autoconfigure.SpringBootApplication; import…

    2024年6月20日
    1.7K00

Leave a Reply

Please Login to Comment