DoytoQuery中的查詢映射方案詳解
引言
DoytoQuery作為一個(gè)ORM框架,在研發(fā)過程中積累了很多全新的思路和解決方案,其中一個(gè)核心方案就是將查詢對象的字段映射為SQL語句中的WHERE條件進(jìn)行動態(tài)查詢,目前支持四種字段映射方式。
讓我們看看如何為以下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. 后綴映射
先定義一個(gè)類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
, 我們需要在列名后加一些特定的后綴作為字段名稱來標(biāo)識對應(yīng)的條件符號。比如,將idIn
映射為id IN (?,?,?)
, 將idGt
映射為id > ?
, 將usernameLike
映射為username LIKE ?
, 還需要定義好對應(yīng)的類型。
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的字段才會被映射,并且多個(gè)條件由AND
連接。
UserQuery userQuery = UserQuery.builder().usernameLike("test").valid(true).build();
這個(gè)userQuery
會被映射為如下查詢語句以及對應(yīng)的參數(shù)。
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
這樣多個(gè)字段由Or
連接的字段會被映射為username = ? OR email = ? OR mobile = ?
。
2.2 將實(shí)現(xiàn)了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]
,然后使用關(guān)鍵字OR
相連而得username = ? OR email = ? OR mobile = ?
.
3. 嵌套查詢映射
嵌套查詢是SQL的另一個(gè)常用特性。在管理菜單樹的menu
表的常見定義中,我們通常定義一個(gè)外鍵parentId
來引向父菜單實(shí)體的id
。
要查詢擁有子菜單的父菜單,我們可以執(zhí)行以下SQL:
SELECT * FROM menu WHERE id IN (SELECT parentId FROM menu WHERE ...)
要查詢某些菜單的子菜單,我們可以執(zhí)行以下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模型里常見的一對多/多對一/多對多關(guān)系. DoytoQuery定義了一個(gè)新的@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"; }
這里有一個(gè)@DomainPath
注解用法介紹。
public class MenuQuery extends PageQuery { // 多對一: 根據(jù)父菜單的條件查詢他們的子菜單 @DomainPath(localField = "parentId", foreignField = "id", value = "menu") MenuQuery parent; // parentId IN (SELECT id FROM menu WHERE ... ) // 一對多: 根據(jù)子菜單的條件查詢父菜單 @DomainPath(localField = "id", foreignField = "parentId", value = "menu") MenuQuery children; // id IN (SELECT parentId FROM menu WHERE ... ) // 多對多: 查詢滿足條件的用戶被授予的菜單 @DomainPath({"menu", "~", "perm", "~", "role", "~", "user"}) UserQuery user; }
4. 直接映射
當(dāng)上述方法都不使用時(shí),還有最后一種將字段映射到條件的方法,就是使用注解@QueryField
定義查詢條件后直接映射。這是DoytoQuery創(chuàng)建時(shí)的第一種映射方式,但是是最后一種推薦的方式,用法如下:
public class MenuQuery extends PageQuery { @QueryField(and = "id = (SELECT parent_id FROM menu WHERE id = ?)") private Integer childId; }
嵌套查詢的這種映射方式在@DomainPath
發(fā)明后就已棄用。
總結(jié)
在本文中,我們介紹了DoytoQuery中的四種字段映射方式。前三種方式不需要編寫任何SQL語句,并且可以涵蓋到關(guān)系數(shù)據(jù)庫開發(fā)中大部分涉及單表查詢的場景。
附錄I: 后綴支持列表
后綴名稱 | 比較符號 | 占位符 | 類型 | 值處理 |
---|---|---|---|---|
(No matching suffix) | = | ? | ||
Not | != | ? | ||
NotLike | NOT LIKE | ? | String | %value% |
Like | LIKE | ? | String | %value% |
Start | LIKE | ? | String | %value |
End | LIKE | ? | String | value% |
NotIn | NOT IN | 非空集合: (?[, ?]); | Collection | |
In | IN | 非空集合(?[, ?]); | Collection | |
NotNull | IS NOT NULL | - | boolean | |
Null | IS NULL | - | boolean | |
Gt | > | ? | ||
Ge | >= | ? | ||
Lt | < | ? | ||
Le | <= | ? | ||
Eq | = | ? |
以上就是DoytoQuery中的查詢映射方案詳解的詳細(xì)內(nèi)容,更多關(guān)于DoytoQuery查詢映射的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
Java多線程的調(diào)度_動力節(jié)點(diǎn)Java學(xué)院整理
有多個(gè)線程,如何控制它們執(zhí)行的先后次序呢?下文給大家分享四種方法及java多線程調(diào)度的實(shí)例代碼,需要的朋友參考下吧2017-05-05Postman實(shí)現(xiàn)傳List<String>集合
這篇文章主要介紹了Postman實(shí)現(xiàn)傳List<String>集合方式,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-08-08關(guān)于Spring自定義XML schema 擴(kuò)展的問題(Spring面試高頻題)
今天給大家分享一道spring高頻率面試題關(guān)于Spring自定義XML schema 擴(kuò)展的問題,今天以spring整合dubbo的實(shí)例給大家詳細(xì)講解下,感興趣的朋友跟隨小編一起看看吧2021-05-05springboot項(xiàng)目編譯提示無效的源發(fā)行版17解決辦法
這篇文章主要給大家介紹了關(guān)于springboot項(xiàng)目編譯提示無效的源發(fā)行版17解決辦法,這個(gè)錯誤意味著你的Spring Boot項(xiàng)目正在使用Java 17這個(gè)版本,但是你的項(xiàng)目中未配置正確的Java版本,需要的朋友可以參考下2023-06-06Java中將一個(gè)列表拆分為多個(gè)較小列表的三種不同方法
有時(shí)候我們需要將大集合按指定的數(shù)量分割成若干個(gè)小集合,這篇文章主要給大家介紹了關(guān)于Java中將一個(gè)列表拆分為多個(gè)較小列表的三種不同方法,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-09-09