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查询映射的资料请关注脚本之家其它相关文章!

相关文章

  • SpringBoot中JPA实现Sort排序的三种方式小结

    SpringBoot中JPA实现Sort排序的三种方式小结

    这篇文章主要介绍了SpringBoot中JPA实现Sort排序的三种方式小结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-11-11
  • Java多线程中断机制三种方法及示例

    Java多线程中断机制三种方法及示例

    这篇文章主要介绍了Java多线程中断机制三种方法及示例,向大家分享了这三种方法的介绍几代码示例,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • Java递归调用如何实现数字的逆序输出方式

    Java递归调用如何实现数字的逆序输出方式

    这篇文章主要介绍了Java递归调用如何实现数字的逆序输出方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-04-04
  • IntelliJ IDEA 2017 汉化包及图文教程

    IntelliJ IDEA 2017 汉化包及图文教程

    这篇文章主要介绍了IntelliJ IDEA 2017 汉化包及图文教程,文中给大家提供两种方法,非常不错,具有参考借鉴价值,需要的朋友参考下吧
    2018-03-03
  • Springboot容器级后置处理器BeanDefinitionRegistryPostProcessor

    Springboot容器级后置处理器BeanDefinitionRegistryPostProcessor

    这篇文章主要介绍了Springboot容器级后置处理器BeanDefinitionRegistryPostProcessor,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2023-01-01
  • Spring中的Aware接口详细解析

    Spring中的Aware接口详细解析

    这篇文章主要介绍了Spring中的Aware接口详细解析,Aware是一个具有标识作用的超级接口,具体实现是有子接口去决定的,但是子接口至少要有一个带一个参数的且返回是空的方法,需要的朋友可以参考下
    2023-12-12
  • Java实现在不同线程中运行的代码实例

    Java实现在不同线程中运行的代码实例

    这篇文章主要介绍了Java实现在不同线程中运行的代码,结合具体实例形式分析了java多线程操作的相关实现技巧,需要的朋友可以参考下
    2017-04-04
  • minio安装部署及使用的详细过程

    minio安装部署及使用的详细过程

    MinIO是一个基于Apache License v2.0开源协议的对象存储服务,下面这篇文章主要给大家介绍了关于minio安装部署及使用的详细过程,文中通过实例代码以及图文介绍的非常详细,需要的朋友可以参考下
    2022-09-09
  • Mybatis分步查询的实现示例

    Mybatis分步查询的实现示例

    本文主要介绍了Mybatis分步查询的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-07-07
  • Spring Boot中使用JDBC Templet的方法教程

    Spring Boot中使用JDBC Templet的方法教程

    这篇文章主要给大家介绍了关于在Spring Boot中使用JDBC Templet的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧。
    2018-03-03

最新评论