DoytoQuery中的查询映射方案详解

 更新时间:2022年12月27日 16:17:56   作者:DOYToWin  
这篇文章主要为大家介绍了DoytoQuery中的查询映射方案详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

引言

DoytoQuery作为一个ORM框架,在研发过程中积累了很多全新的思路和解决方案,其中一个核心方案就是将查询对象的字段映射为SQL语句中的WHERE条件进行动态查询,目前支持四种字段映射方式。

让我们看看如何为以下UserEntity编写查询对象:

@Getter
@Setter
@Entity
public class UserEntity extends AbstractPersistable<Integer> {
    private String username;
    private String email;
    private String mobile;
    private String password;
    private String nickname;
    private Boolean valid;
}

四种字段映射方式详解

1. 后缀映射

先定义一个类UserQuery, 对于一些常见的查询条件,比如id = ?username = ? and valid = ?等,我们只需要在UserQuery类中定义如下字段即可。

@Getter
@Setter
@SuperBuilder
@NoArgsConstructor
@AllArgsConstructor
public class UserQuery extends PageQuery {
    private Integer id;
    private String username;
    private Boolean valid;
}

像其他一些常用的比较符号. [NOT] LIKE><!=>=<=IS [NOT] NULL[NOT] IN, 我们需要在列名后加一些特定的后缀作为字段名称来标识对应的条件符号。比如,将idIn映射为id IN (?,?,?), 将idGt映射为id > ?, 将usernameLike映射为username LIKE ?, 还需要定义好对应的类型。

public class UserQuery extends PageQuery {
    private Integer id;
    private String username;
    private Boolean valid;
    private List<Integer> idIn;
    private Integer idGt;
    private String usernameLike;
}

只有值不为NULL的字段才会被映射,并且多个条件由AND连接。

UserQuery userQuery = UserQuery.builder().usernameLike("test").valid(true).build();

这个userQuery会被映射为如下查询语句以及对应的参数。

SELECT id, username, email, mobile, password, nickname, valid FROM user WHERE username LIKE ? and valid = ?
-- With parameters: ["%test%", true] 

所有支持的后缀详见附录I。

2. OR映射

OR语句也是SQL里一种常用的查询方式,DoytoQuery支持的方式有两种。

2.1 将含Or的字段映射为OR语句

usernameOrEmailOrMobile这样多个字段由Or连接的字段会被映射为username = ? OR email = ? OR mobile = ?

2.2 将实现了Or的对象映射为OR语句

public interface Or {
}
public class AccountOr implements Or {
    private String username;
    private String email;
    private String mobile;
}
public class UserQuery {
    private AccountOr account;
}

遍历AccountOr中的字段可以得到[username, email, mobile],然后使用关键字OR相连而得username = ? OR email = ? OR mobile = ?.

3. 嵌套查询映射

嵌套查询是SQL的另一个常用特性。在管理菜单树的menu表的常见定义中,我们通常定义一个外键parentId来引向父菜单实体的id

要查询拥有子菜单的父菜单,我们可以执行以下SQL:

SELECT * FROM menu WHERE id IN (SELECT parentId FROM menu WHERE ...)

要查询某些菜单的子菜单,我们可以执行以下SQL:

SELECT * FROM menu WHERE parentId IN (SELECT id FROM menu WHERE ...)

这条语句用于查询指定用户拥有的菜单:

SELECT * FROM menu WHERE id IN (
    SELECT menu_id FROM a_perm_and_menu WHERE perm_id IN (
        SELECT perm_id FROM a_role_and_perm WHERE role_id IN (
            SELECT role_id FROM a_user_and_role WHERE user_id IN (
                SELECT id FROM t_user WHERE id = ?
))))

这些都是ERM模型里常见的一对多/多对一/多对多关系. DoytoQuery定义了一个新的@DomainPath注解来映射这种嵌套查询。

@Target(FIELD)
@Retention(RUNTIME)
public @interface DomainPath {
    // To describe how to route from the host domain to the target domain.
    String[] value();
    String localField() default "id";
    String foreignField() default "id";
}

这里有一个@DomainPath注解用法介绍。

public class MenuQuery extends PageQuery {
    // 多对一: 根据父菜单的条件查询他们的子菜单
    @DomainPath(localField = "parentId", foreignField = "id", value = "menu")
    MenuQuery parent;      // parentId   IN (SELECT      id   FROM     menu  WHERE ... )
    // 一对多: 根据子菜单的条件查询父菜单
    @DomainPath(localField = "id", foreignField = "parentId", value = "menu")
    MenuQuery children;    // id   IN (SELECT      parentId   FROM     menu  WHERE ... )
    // 多对多: 查询满足条件的用户被授予的菜单
    @DomainPath({"menu", "~", "perm",  "~", "role", "~", "user"})
    UserQuery user;
}

4. 直接映射

当上述方法都不使用时,还有最后一种将字段映射到条件的方法,就是使用注解@QueryField定义查询条件后直接映射。这是DoytoQuery创建时的第一种映射方式,但是是最后一种推荐的方式,用法如下:

public class MenuQuery extends PageQuery {
    @QueryField(and = "id = (SELECT parent_id FROM menu WHERE id = ?)")
    private Integer childId;
}

嵌套查询的这种映射方式在@DomainPath发明后就已弃用。

总结

在本文中,我们介绍了DoytoQuery中的四种字段映射方式。前三种方式不需要编写任何SQL语句,并且可以涵盖到关系数据库开发中大部分涉及单表查询的场景。

附录I: 后缀支持列表

后缀名称比较符号占位符类型值处理
(No matching
suffix)
=
Not!=?
NotLikeNOT LIKE?String%value%
LikeLIKE?String%value%
StartLIKE?String%value
EndLIKE?Stringvalue%
NotInNOT IN

非空集合: (?[, ?]);
空集合则忽略

Collection
InIN

非空集合(?[, ?]);
空集合: (null)

Collection
NotNullIS NOT NULL-boolean
NullIS NULL-boolean
Gt>?
Ge>=?
Lt<?
Le<=?
Eq=?

以上就是DoytoQuery中的查询映射方案详解的详细内容,更多关于DoytoQuery查询映射的资料请关注脚本之家其它相关文章!

相关文章

  • Java多线程的调度_动力节点Java学院整理

    Java多线程的调度_动力节点Java学院整理

    有多个线程,如何控制它们执行的先后次序呢?下文给大家分享四种方法及java多线程调度的实例代码,需要的朋友参考下吧
    2017-05-05
  • Postman实现传List<String>集合

    Postman实现传List<String>集合

    这篇文章主要介绍了Postman实现传List<String>集合方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-08-08
  • 关于Spring自定义XML schema 扩展的问题(Spring面试高频题)

    关于Spring自定义XML schema 扩展的问题(Spring面试高频题)

    今天给大家分享一道spring高频率面试题关于Spring自定义XML schema 扩展的问题,今天以spring整合dubbo的实例给大家详细讲解下,感兴趣的朋友跟随小编一起看看吧
    2021-05-05
  • springboot项目编译提示无效的源发行版17解决办法

    springboot项目编译提示无效的源发行版17解决办法

    这篇文章主要给大家介绍了关于springboot项目编译提示无效的源发行版17解决办法,这个错误意味着你的Spring Boot项目正在使用Java 17这个版本,但是你的项目中未配置正确的Java版本,需要的朋友可以参考下
    2023-06-06
  • java并发之Lock接口的深入讲解

    java并发之Lock接口的深入讲解

    从Java 5之后,在java.util.concurrent.locks包下提供了另外一种方式来实现同步访问.那就是Lock,这篇文章主要给大家介绍了关于java并发之Lock接口的相关资料,需要的朋友可以参考下
    2021-08-08
  • Java面试题冲刺第二十一天--JVM

    Java面试题冲刺第二十一天--JVM

    这篇文章主要为大家分享了最有价值的三道关于JVM的面试题,涵盖内容全面,包括数据结构和算法相关的题目、经典面试编程题等,感兴趣的小伙伴们可以参考一下
    2021-08-08
  • Java 注解学习笔记

    Java 注解学习笔记

    这篇文章主要介绍了Java 注解的相关资料,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下
    2021-03-03
  • Java中将一个列表拆分为多个较小列表的三种不同方法

    Java中将一个列表拆分为多个较小列表的三种不同方法

    有时候我们需要将大集合按指定的数量分割成若干个小集合,这篇文章主要给大家介绍了关于Java中将一个列表拆分为多个较小列表的三种不同方法,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2023-09-09
  • 一文详解jvm中的引用类型

    一文详解jvm中的引用类型

    在Java中对象以引用来指向JVM的内存区块,这里我们总结了强引用、软引用、弱引用和假象引用(幽灵引用),下面这篇文章主要给大家介绍了关于jvm中引用类型的相关资料,需要的朋友可以参考下
    2024-04-04
  • Java实现冒泡排序简单示例

    Java实现冒泡排序简单示例

    冒泡排序(Bubble Sort)是一种简单的排序算法,它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来,下面这篇文章主要给大家介绍了关于Java实现冒泡排序的相关资料,需要的朋友可以参考下
    2023-06-06

最新评论