### Solon Controller Example Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/guide/solon.md A basic Solon controller with a GET mapping for '/hello' that returns 'Hello World'. ```java @Controller @Mapping("/test") public class TestController { @Mapping(value = "/hello",method = MethodType.GET) public String hello(){ return "Hello World"; } } ``` -------------------------------- ### Name Conversion Examples for Java Properties to Database Columns Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/framework/mapping-db.md Demonstrates various name conversion strategies for mapping Java properties (like `userAge`) to database column names. These examples show the output of different `NameConversion` implementations. ```log property:userAge-->conversion:DefaultNameConversion-->column:userAge property:userAge-->conversion:UnderlinedNameConversion-->column:user_age property:userAge-->conversion:UpperUnderlinedNameConversion-->column:USER_AGE property:userAge-->conversion:LowerCamelCaseNameConversion-->column:userAge property:userAge-->conversion:UpperCamelCaseNameConversion-->column:UserAge ``` -------------------------------- ### Database and Logging Configuration Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/guide/solon.md Example of application.yml configuration for database connection (db1) and Solon logging levels. ```yaml db1: jdbcUrl: jdbc:mysql://127.0.0.1:3306/easy-query-test?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver easy-query: # Configure custom log # log-class: ... db1: # Supports mysql pgsql h2 mssql dameng mssql_row_number kingbase_es, other databases are being adapted database: mysql # Supports underlined default lower_camel_case upper_camel_case upper_underlined name-conversion: underlined # Throw exception on physical deletion, not including manual SQL delete-throw: true # Entity mapping to dto/vo uses property matching mode # Supports property_only column_only column_and_property property_first mapping-strategy: property_first # Insert column strategy all_columns only_not_null_columns only_null_columns insert-strategy: only_not_null_columns # Update column strategy all_columns only_not_null_columns only_null_columns update-strategy: all_columns # Still query large fields. If not querying, it's recommended to set updateIgnore to prevent update allcolumn from changing it to null query-large-column: true # Error on update/delete without version number no-version-error: true # Sharding connection mode system_auto memory_strictly connection_strictly # connection-mode: ... # max-sharding-query-limit: ... # executor-maximum-pool-size: ... # executor-core-pool-size: ... # throw-if-route-not-match: ... # sharding-execute-timeout-millis: ... # max-sharding-route-count: ... # executor-queue-size: ... # default-data-source-name: ... # default-data-source-merge-pool-size: ... # multi-conn-wait-timeout-millis: ... # warning-busy: ... # insert-batch-threshold: ... # update-batch-threshold: ... # print-sql: ... # start-time-job: ... # relation-group-size: ... # warning-column-miss: ... # sharding-fetch-size: ... # Sharding query mode in transaction serializable concurrency # sharding-query-in-transaction: .... # Logger level configuration example. If print-sql is configured but the corresponding log is not configured, it will not print solon.logging.logger: "root": #Default logger configuration level: TRACE "com.zaxxer.hikari": level: WARN ``` -------------------------------- ### SQL for Initial Queryable Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/ability/select/expression.md The SQL equivalent of starting a query with queryable(). ```sql select * from help_province ``` -------------------------------- ### SQL Equivalent for Comprehensive Offset Example Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/func/offset.md This SQL query shows the equivalent of the complex Java offset example, using LAG and LEAD functions with PARTITION BY and ORDER BY clauses. ```sql SELECT t.`type` AS `value1`, LAG(t.`type`, 1) OVER (ORDER BY t.`type` ASC, t.`code` DESC) AS `value2` , LEAD(t.`open_time`, 1) OVER (ORDER BY t.`type` ASC, t.`code` DESC) AS `value3` , LEAD(t.`open_time`, 1) OVER (PARTITION BY t.`bank_id` ORDER BY t.`type` ASC, t.`code` DESC) AS `value4` , LEAD(t.`open_time`, 1, '2025-01-01 00:00') OVER (PARTITION BY t.`bank_id` ORDER BY t.`type` ASC, t.`code` DESC) AS `value5` , IFNULL(LEAD(t.`open_time`, 1) OVER (PARTITION BY t.`bank_id` ORDER BY t.`type` ASC, t.`code` DESC), '2025-01-01 00:00') AS `value6` , IFNULL(LEAD(t.`open_time`, 1, t.`open_time`) OVER (PARTITION BY t.`bank_id` ORDER BY t.`type` ASC, t.`code` DESC), '2025-01-01 00:00') AS `value7` FROM `t_bank_card` t ``` -------------------------------- ### SQL Query Log Example Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/guide/spring-boot.md Example log output showing the SQL query executed and its parameters. Useful for debugging and understanding query execution. ```log ==> Preparing: SELECT `id`,`name`,`create_time`,`register_money` FROM `t_company` WHERE `name` LIKE ? ==> Parameters: %123%(String) <== Time Elapsed: 5(ms) <== Total: 0 ``` -------------------------------- ### Example JSON Structure Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/dto-query/map2.md Illustrates a nested JSON structure representing user, roles, and menu information. ```json { "user": { "name": "小明", "age": 12, "roles": [ { "name": "管理员", "enable": true, "top3Menus": "用户管理,部门管理,企业管理", "menuCount": 6 } ] } } ``` -------------------------------- ### SQL Query Example Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/dto-query/question.md A basic SQL query to select all records from a user table. ```sql SELECT * FROM user ``` -------------------------------- ### HTTP Request Example Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/guide/sb-multi-datasource.md This is an example of an HTTP GET request to the '/api/test/dsc' endpoint, which is configured to use the 'ds2' data source via the @DS annotation. ```shell http://localhost:8081/api/test/dsc ``` -------------------------------- ### Initialize Easy-Query Client and Perform Query Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/guide/kapt.md Set up the Easy-Query client with a data source and execute a sample query using the generated proxy. ```java import com.easy.query.api.proxy.client.DefaultEasyProxyQuery import com.easy.query.core.bootstrapper.EasyQueryBootstrapper import com.easy.query.core.logging.LogFactory import com.easy.query.mysql.config.MySQLDatabaseConfiguration import com.zaxxer.hikari.HikariDataSource import entity.proxy.TopicProxy fun main(args: Array) { println("Hello World!") var hikariDataSource = HikariDataSource() hikariDataSource.jdbcUrl = "jdbc:mysql://127.0.0.1:3306/easy-query-test?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true"; hikariDataSource.username = "root"; hikariDataSource.password = "root"; hikariDataSource.driverClassName = "com.mysql.cj.jdbc.Driver"; hikariDataSource.maximumPoolSize = 20; LogFactory.useStdOutLogging(); var easyQueryClient = EasyQueryBootstrapper.defaultBuilderConfiguration() .setDefaultDataSource(hikariDataSource) .useDatabaseConfigure(MySQLDatabaseConfiguration()) .build() //If ProxyEntityAvailable is implemented (can be generated using the plugin, then you can use EasyEntityQuery) var easyEntityQuery = DefaultEasyEntityQuery(easyQueryClient) var toList2 = easyEntityQuery.queryable(topic) .where { it.id().eq("1") it.stars3()eq(,1) } .toList() } ``` -------------------------------- ### EasyQuery Default Project Configuration File Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/plugin/setting.md This snippet shows the default structure and example configurations for the `easy-query.setting` file. It includes settings for DTO annotations, startup inspections, SQL formatting, and lambda tips. ```text # EasyQuery 默认项目配置文件 # 在此处添加您的自定义配置 # 可配置的内容请参见 https://github.com/xuejmnet/easy-query-plugin # 配置语法参见 https://doc.hutool.cn/pages/setting/example # DTO是否保留Column注解 true/false ## DTO是否保留 @Column 注解, 当字段映射为 属性优先/属性唯一 的时候可以不用保留 @Column 注解 dto.keepAnnoColumn=true # 启动项配置 ## 启动时是否检查扫描问题 startup.runInspection=true # 具体参考 com.alibaba.druid.util.FnvHash.DbType 如果是generic那么还是原先的格式化 如果不是generic且未匹配到则使用DbType.other sql.format=postgresql,mysql,sqlserver,oracle,h2,sqlite # lambda快速提示 lambda.tip= # dto配置忽略json dto.columns.ignores= # 数据库生成配置文件 sql.generate = ``` -------------------------------- ### Pagination Query Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/startup/quick-start.md Perform a paginated query to retrieve data in chunks. This example shows how to get the first page with 20 items per page. See the pagination chapter for more features. ```java //Query pagination EasyPageResult Company = entityQuery.queryable(Company.class).where(c -> { c.id().eq("1"); c.name().like("公司"); }).toPageResult(1, 20); ``` -------------------------------- ### Count Column Values Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/func/general.md Use the count function to get the quantity of existing values in a column. The distinct parameter can be used to count unique values. This example also demonstrates filtering counts based on a condition. ```java List> list = easyEntityQuery.queryable(BlogEntity.class) .where(t_blog -> { t_blog.content().like("abc"); }).select(t_blog -> Select.DRAFT.of( t_blog.id().count(),//count(id) t_blog.title().count(true),//count(distinct title) t_blog.title().count().filter(() -> {//count titles that are not "scary" t_blog.title().ne("恐怖"); }) )).toList(); ``` -------------------------------- ### Initialize EasyQuery with MySQL Data Source Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/startup/quick-start.md Sets up the EasyQuery client with a HikariCP data source for MySQL and synchronizes database tables. This is the initial setup for using EasyQuery. ```java package com.easy.query.console; import com.easy.query.api.proxy.client.DefaultEasyEntityQuery; import com.easy.query.api.proxy.client.EasyEntityQuery; import com.easy.query.console.entity.Company; import com.easy.query.console.entity.SysUser; import com.easy.query.core.api.client.EasyQueryClient; import com.easy.query.core.basic.api.database.CodeFirstCommand; import com.easy.query.core.basic.api.database.DatabaseCodeFirst; import com.easy.query.core.bootstrapper.EasyQueryBootstrapper; import com.easy.query.core.logging.LogFactory; import com.easy.query.mysql.config.MySQLDatabaseConfiguration; import com.zaxxer.hikari.HikariDataSource; import javax.sql.DataSource; import java.util.Arrays; public class Main { private static EasyEntityQuery entityQuery; public static void main(String[] args) { LogFactory.useStdOutLogging(); DataSource dataSource = getDataSource(); EasyQueryClient client = EasyQueryBootstrapper.defaultBuilderConfiguration() .setDefaultDataSource(dataSource) .optionConfigure(op -> { //Perform a series of optional configurations //op.setPrintSql(true); }) .useDatabaseConfigure(new MySQLDatabaseConfiguration()) .build(); entityQuery = new DefaultEasyEntityQuery(client); DatabaseCodeFirst databaseCodeFirst = entityQuery.getDatabaseCodeFirst(); //Create database if it doesn't exist databaseCodeFirst.createDatabaseIfNotExists(); //Automatically synchronize database tables CodeFirstCommand codeFirstCommand = databaseCodeFirst.syncTableCommand(Arrays.asList(Company.class, SysUser.class)); //Execute command codeFirstCommand.executeWithTransaction(arg->{ System.out.println(arg.sql); arg.commit(); }); } /** * Initialize data source * @return */ private static DataSource getDataSource(){ HikariDataSource dataSource = new HikariDataSource(); dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/eq_db?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true"); dataSource.setUsername("root"); dataSource.setPassword("root"); dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); dataSource.setMaximumPoolSize(20); return dataSource; } } ``` -------------------------------- ### Get User Menu IDs and Names using NavigateFlat Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/dto-query/map1.md Fetch both the IDs and names of menus owned by users. This example demonstrates selecting specific fields from deeply nested entities using flatElement() with a fetcher. ```java List menuIdNames = easyEntityQuery.queryable(SysUser.class) .where(s -> s.name().like("小明")) .toList(s -> s.roles().flatElement().menus().flatElement(x->x.FETCHER.id().name())); ``` -------------------------------- ### Manual Batch Insert Example Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/ability/batch.md Demonstrates how to perform a manual batch insert using the `batch()` method on an `insertable` query. Note the potential for inaccurate return values when using batch mode. ```java List topics = createLargeTopicList(); // Manual batch insert easyEntityQuery.insertable(topics).batch().executeRows(); ``` -------------------------------- ### User Query Examples Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/navigate.md Demonstrates fetching the first User record or null, and handling exceptions when querying for a single record that might have multiple matches. ```java @Test public void testOne() { //查询第一条 User firstUser = easyEntityQuery.queryable(User.class).firstOrNull(); Assertions.assertNotNull(firstUser); Assertions.assertThrows(EasyQuerySingleMoreElementException.class, () -> { //只查询一条,如果有多条则抛出异常 easyEntityQuery.queryable(User.class).singleOrNull(); }); Assertions.assertTrue(exists); } ``` -------------------------------- ### Filter users by first bank card being Industrial and Commercial Bank of China Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/demo/quick-query.md Filters a list of SysUser objects to include only those whose first opened bank card is with '工商银行' (Industrial and Commercial Bank of China). The example uses `orderBy` and `first` to get the earliest opened bank card. ```java List list = easyEntityQuery.queryable(SysUser.class) .where(user -> { //用户的银行卡中第一个开户银行卡是工商银行的 user.bankCards().orderBy(x->x.openTime().asc()).first().bank().name().eq("工商银行"); }).toList(); ``` ```sql SELECT t.`id`, t.`name`, t.`phone`, t.`age`, t.`create_time` FROM `t_sys_user` t LEFT JOIN ( SELECT t2.`id` AS `id`, t2.`uid` AS `uid`, t2.`code` AS `code`, t2.`type` AS `type`, t2.`bank_id` AS `bank_id`, t2.`open_time` AS `open_time` FROM (SELECT t1.`id`, t1.`uid`, t1.`code`, t1.`type`, t1.`bank_id`, t1.`open_time`, (ROW_NUMBER() OVER (PARTITION BY t1.`uid` ORDER BY t1.`open_time` ASC)) AS `__row__` FROM `t_bank_card` t1) t2 WHERE t2.`__row__` = 1 ) t4 ON t4.`uid` = t.`id` INNER JOIN `t_bank` t5 ON t5.`id` = t4.`bank_id` WHERE t5.`name` = '工商银行' ``` -------------------------------- ### Solon Application Startup Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/guide/solon.md The main method to start a Solon application, loading configurations from 'application.yml'. Includes the access URL and expected response. ```java public class Main { public static void main(String[] args) { Solon.start(Main.class,args,(app)->{ app.cfg().loadAdd("application.yml"); }); } } //Access URL http://localhost:8080/test/hello //Returns Hello World ``` -------------------------------- ### Substring Extraction Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/func/string.md Demonstrates the subString function for extracting parts of a string. It takes a starting position (0-indexed) and a length. Note that database indices typically start at 1, while Java indices start at 0. ```java List> list = easyEntityQuery.queryable(Topic.class) .select(topic -> Select.DRAFT.of( topic.id().subString(0,2), topic.id().subString(0,topic.stars()) )).toList(); ``` -------------------------------- ### Request JSON Data Example Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/savable/set-save-key.md Example of JSON data representing a bank entity with associated bank cards. ```json { "id": "1", "name": "ICBC", "address": "City Plaza No. 1", "saveBankCards": [ { "id": "2", "type": "Savings Card", "code": "123" }, { "id": "3", "type": "Credit Card", "code": "456" } ] } ``` -------------------------------- ### Java APT Processor Implementation Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/practice/apt/auto-props.md This snippet shows a basic Java APT processor setup. It initializes necessary Javac and processing environment utilities. It's designed to process annotations like AutoProperty. ```java package com.eq.autopops; import com.eq.autopops.process.AutoProperty; import com.sun.source.util.Trees; import com.sun.tools.javac.api.JavacTrees; import com.sun.tools.javac.processing.JavacProcessingEnvironment; import com.sun.tools.javac.tree.TreeMaker; import com.sun.tools.javac.util.Context; import com.sun.tools.javac.util.Names; import javax.annotation.processing.AbstractProcessor; import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; import javax.lang.model.SourceVersion; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; import javax.tools.Diagnostic; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Proxy; import java.util.HashSet; import java.util.Set; /** * create time 2025/11/20 21:42 * File description * * @author xuejiaming */ @SupportedAnnotationTypes({"com.eq.autopops.process.AutoProperty"}) @SupportedSourceVersion(SourceVersion.RELEASE_8) public class MyAptProcessor extends AbstractProcessor { private JavacTrees javacTrees; private TreeMaker treeMaker; private Names names; private Elements elementUtils; private Types typeUtils; private Trees trees; @Override public synchronized void init(ProcessingEnvironment processingEnv) { super.init(processingEnv); JavacProcessingEnvironment javacProcessingEnvironment = getJavacProcessingEnvironment(processingEnv); Context context = javacProcessingEnvironment.getContext(); this.javacTrees = JavacTrees.instance(context); this.treeMaker = TreeMaker.instance(context); this.names = Names.instance(context); this.elementUtils = processingEnv.getElementUtils(); this.typeUtils = processingEnv.getTypeUtils(); this.trees = Trees.instance(javacProcessingEnvironment); } /** * This class casts the given processing environment to a JavacProcessingEnvironment. In case of * gradle incremental compilation, the delegate ProcessingEnvironment of the gradle wrapper is returned. */ public JavacProcessingEnvironment getJavacProcessingEnvironment(Object procEnv) { if (procEnv instanceof JavacProcessingEnvironment) return (JavacProcessingEnvironment) procEnv; // try to find a "delegate" field in the object, and use this to try to obtain a JavacProcessingEnvironment for (Class procEnvClass = procEnv.getClass(); procEnvClass != null; procEnvClass = procEnvClass.getSuperclass()) { Object delegate = tryGetDelegateField(procEnvClass, procEnv); if (delegate == null) delegate = tryGetProxyDelegateToField(procEnvClass, procEnv); if (delegate == null) delegate = tryGetProcessingEnvField(procEnvClass, procEnv); if (delegate != null) return getJavacProcessingEnvironment(delegate); // delegate field was not found, try on superclass } processingEnv.getMessager().printMessage(Diagnostic.Kind.WARNING, "Can't get the delegate of the gradle IncrementalProcessingEnvironment. Lombok won't work."); return null; } /** * Gradle incremental processing */ private Object tryGetDelegateField(Class delegateClass, Object instance) { try { return Permit.getField(delegateClass, "delegate").get(instance); } catch (Exception e) { return null; } } /** * Kotlin incremental processing */ private Object tryGetProcessingEnvField(Class delegateClass, Object instance) { try { return Permit.getField(delegateClass, "processingEnv").get(instance); } catch (Exception e) { return null; } } /** * IntelliJ IDEA >= 2020.3 */ private Object tryGetProxyDelegateToField(Class delegateClass, Object instance) { try { InvocationHandler handler = Proxy.getInvocationHandler(instance); return Permit.getField(handler.getClass(), "val$delegateTo").get(handler); } catch (Exception e) { return null; } } @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { Set sets = roundEnv.getElementsAnnotatedWith(AutoProperty.class); EntityMetadataContext entityMetadataContext = new EntityMetadataContext(treeMaker, names, javacTrees, elementUtils, typeUtils); // AutoPropGroupContext autoPropGroupContext = new AutoPropGroupContext(elementUtils); ``` -------------------------------- ### Run Easy-Query with Proxy Mode Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/guide/kapt.md This Kotlin `main` function demonstrates how to initialize Easy-Query with a HikariCP data source and perform a query using the generated proxy. ```java import com.easy.query.api.proxy.client.DefaultEasyProxyQuery import com.easy.query.core.bootstrapper.EasyQueryBootstrapper import com.easy.query.core.logging.LogFactory import com.easy.query.mysql.config.MySQLDatabaseConfiguration import com.zaxxer.hikari.HikariDataSource import entity.proxy.TopicProxy fun main(args: Array) { println("Hello World!") var hikariDataSource = HikariDataSource() hikariDataSource.jdbcUrl = "jdbc:mysql://127.0.0.1:3306/easy-query-test?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true"; hikariDataSource.username = "root"; hikariDataSource.password = "root"; hikariDataSource.driverClassName = "com.mysql.cj.jdbc.Driver"; hikariDataSource.maximumPoolSize = 20; LogFactory.useStdOutLogging(); var easyQueryClient = EasyQueryBootstrapper.defaultBuilderConfiguration() .setDefaultDataSource(hikariDataSource) .useDatabaseConfigure(MySQLDatabaseConfiguration()) .build() //如果实现了ProxyEntityAvailable(可用插件生成则可以使用EasyEntityQuery) var easyEntityQuery = DefaultEasyEntityQuery(easyQueryClient) var toList2 = easyEntityQuery.queryable(topic) .where { it.id().eq("1") it.stars3()eq(,1) } .toList() } ``` -------------------------------- ### Custom ValueAutoConverterProvider Example (Commented Out) Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/prop/global-value-converter.md An example of a custom ValueAutoConverterProvider that supports enums and types implementing IAutoRegister. This is for demonstration purposes. ```java // public class MyValueAutoConverterProvider implements ValueAutoConverterProvider { // @Override // public boolean isSupport(@NotNull Class clazz, @NotNull Class propertyType) { // return Enum.class.isAssignableFrom(propertyType) // || IAutoRegister.class.isAssignableFrom(propertyType); // } // } ``` -------------------------------- ### Database Schema for Easy-Trans Demo Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/framework/easy-trans.md SQL script to create the 'easy_trans_demo' database and necessary tables ('help_code', 'sys_user') for demonstration purposes. ```sql CREATE DATABASE IF NOT EXISTS easy_trans_demo CHARACTER SET 'utf8mb4'; USE easy_trans_demo; create table help_code ( code varchar(32) not null comment 'code'primary key, type int not null comment 'type', name varchar(50) not null comment 'Chinese value' )comment 'dictionary table'; insert into help_code values('1',1,'Male'); insert into help_code values('2',1,'Female'); insert into help_code values('3',2,'Administrator'); insert into help_code values('4',2,'Normal User'); create table sys_user ( id varchar(32) not null comment 'id'primary key, name varchar(50) not null comment 'name', sex varchar(50) not null comment 'gender', type varchar(50) not null comment 'user type' )comment 'user table'; insert into sys_user values('1','XiaoMing','2','3'); insert into sys_user values('2','XiaoGang','1','4'); ``` -------------------------------- ### Modified Request JSON Data Example Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/savable/set-save-key.md Example of modified JSON data, showing a deleted card and an added new card. ```json { "id": "1", "name": "ICBC", "address": "City Plaza No. 1", "saveBankCards": [ // { // "id": "2", // "type": "Savings Card", // "code": "123" // }, { "id": "3", "type": "Credit Card", "code": "456" }, { "id": "4", "type": "Debit Card", "code": "789" } ] } ``` -------------------------------- ### Paginated JOIN Query Example Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/dto-query/question.md An example of a paginated JOIN query that can lead to incorrect pagination semantics by limiting results after the join. ```sql SELECT * FROM user u LEFT JOIN paper p ON p.user_id = u.id LIMIT 10 ``` -------------------------------- ### Database Initialization and Table Synchronization Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/code-first/quick-start.md Initializes the Easy-Query client, creates the database if it doesn't exist, and synchronizes the Company and SysUser tables using the code-first approach. This snippet includes data source configuration and command execution. ```java package com.easy.query.console; import com.easy.query.api.proxy.client.DefaultEasyEntityQuery; import com.easy.query.api.proxy.client.EasyEntityQuery; import com.easy.query.console.entity.Company; import com.easy.query.console.entity.SysUser; import com.easy.query.console.vo.CompanyNameAndUserNameVO; import com.easy.query.console.vo.proxy.CompanyNameAndUserNameVOProxy; import com.easy.query.core.api.client.EasyQueryClient; import com.easy.query.core.api.pagination.EasyPageResult; import com.easy.query.core.basic.api.database.CodeFirstCommand; import com.easy.query.core.basic.api.database.DatabaseCodeFirst; import com.easy.query.core.bootstrapper.EasyQueryBootstrapper; import com.easy.query.core.logging.LogFactory; import com.easy.query.core.proxy.core.draft.Draft2; import com.easy.query.core.proxy.sql.Select; import com.easy.query.mysql.config.MySQLDatabaseConfiguration; import com.zaxxer.hikari.HikariDataSource; import javax.sql.DataSource; import java.util.Arrays; import java.util.List; public class Main { private static EasyEntityQuery entityQuery; public static void main(String[] args) { LogFactory.useStdOutLogging(); DataSource dataSource = getDataSource(); EasyQueryClient client = EasyQueryBootstrapper.defaultBuilderConfiguration() .setDefaultDataSource(dataSource) .optionConfigure(op -> { //进行一系列可以选择的配置 //op.setPrintSql(true); }) .useDatabaseConfigure(new MySQLDatabaseConfiguration()) .build(); entityQuery = new DefaultEasyEntityQuery(client); DatabaseCodeFirst databaseCodeFirst = entityQuery.getDatabaseCodeFirst(); //如果不存在数据库则创建 databaseCodeFirst.createDatabaseIfNotExists(); //自动同步数据库表 CodeFirstCommand command = databaseCodeFirst.syncTableCommand(Arrays.asList(Company.class, SysUser.class)); //执行命令 command.executeWithTransaction(arg -> { System.out.println(arg.sql); arg.commit(); }); } /** * 初始化数据源 * * @return */ private static DataSource getDataSource() { HikariDataSource dataSource = new HikariDataSource(); dataSource.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/eq_db?serverTimezone=GMT%2B8&characterEncoding=utf-8&useSSL=false&allowMultiQueries=true&rewriteBatchedStatements=true"); dataSource.setUsername("root"); dataSource.setPassword("root"); dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver"); dataSource.setMaximumPoolSize(20); return dataSource; } } ``` -------------------------------- ### Example Tree List JSON Output Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/startup/step4.md This is an example of the JSON output format produced by the `toTreeList` method, representing a nested structure of comments. ```json [ { "id": "03abe9c8-adf1-4934-ae53-3b52c7c3eb2d", "parentId": "0", "content": "写得真详细", "userId": "3b63ddd9-b038-4c24-969e-8b478fe862a5", "postId": "73f5d341-c6df-43a1-afcd-e246c4d1fcc9", "createAt": "2025-08-07T06:42:43.526", "children": [ { "id": "01225d2f-e1a5-46d8-8ef9-535b7b1b7754", "parentId": "03abe9c8-adf1-4934-ae53-3b52c7c3eb2d", "content": "@用户E 具体是指哪方面?", "userId": "3b63ddd9-b038-4c24-969e-8b478fe862a5", "postId": "73f5d341-c6df-43a1-afcd-e246c4d1fcc9", "createAt": "2025-08-07T14:42:43.526", "children": [ { "id": "1bccba2c-7cff-43af-b117-2e518be4422a", "parentId": "01225d2f-e1a5-46d8-8ef9-535b7b1b7754", "content": "@用户E 你是指...", "userId": "3b63ddd9-b038-4c24-969e-8b478fe862a5", "postId": "73f5d341-c6df-43a1-afcd-e246c4d1fcc9", "createAt": "2025-08-07T19:42:43.526", "children": [], "user": null } ], "user": null } ], "user": null } ...... ] ``` -------------------------------- ### MyStarterConfigurer for Service Registration Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/adv/jdbc-listener.md Configures the Spring Boot starter by registering the HttpLogRequest instance and the LogSlowSQLListener with Easy-Query's dependency injection container. ```java @Component public class MyStarterConfigurer implements StarterConfigurer { @Autowired private HttpLogRequest httpLogRequest; @Override public void configure(ServiceCollection services) { services.addService(httpLogRequest);//直接注册实例到easy-query内部的依赖注入容器里面 services.addService(JdbcExecutorListener.class, LogSlowSQLListener.class); } } ``` -------------------------------- ### Enable Console Logging Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/framework/logging.md Use System.out.println and System.err.println for framework logging. ```java LogFactory.useStdOutLogging(); ``` -------------------------------- ### Example Enum with @EnumValue Annotation Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/adv/value-converter.md An example enum `TopicTypeEnum` where the `code` field is annotated with @EnumValue, indicating it's the value to be used for serialization and deserialization. ```java public enum TopicTypeEnum { STUDENT(1), TEACHER(3), CLASSER(9); @EnumValue private final Integer code; TopicTypeEnum(Integer code){ this.code = code; } @Override public Integer getCode() { return code; } } ``` -------------------------------- ### Dependency Injection for Starter Configuration Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/adv/jdbc-listener.md This Java class configures dependency injection for the JDBC listener. It implements StarterConfigurer to add the LogSlowSQLListener to the service collection, using a configured slow milliseconds threshold from DbProperties. ```java //Dependency injection public class MyStarterConfigurer implements StarterConfigurer { private final DbProperties dbProperties; public MyStarterConfigurer(DbProperties dbProperties) { this.dbProperties = dbProperties; } @Override public void configure(ServiceCollection services) { services.addService(JdbcExecutorListener.class, new LogSlowSQLListener(dbProperties.getSlowMillis())); } } ``` -------------------------------- ### Example Post Data Structure Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/startup/step2.md An example JSON object representing a post, including its ID, title, content, user information, publication date, and a list of comments. ```json { "id": "0c6ab3ab-29a4-4320-a08e-195bdac27095", "title": "JVM调优实战", "content": "# 这是用户用户C的帖子内容\n包含丰富的文本内容...", "userId": "2e509ef4-0282-448f-ace0-43501d46ccf4", "publishAt": "2025-08-04T23:42:43.525", "userName": "2e509ef4-0282-448f-ace0-43501d46ccf4", "categoryNames": "娱乐,教育", "commentList": [ { "id": "2d3643e6-8fb5-4a2b-a0bc-1c92030bfa34", "parentId": "0", "content": "完全同意你的观点", "createAt": "2025-08-07T00:42:43.526" }, { "id": "5f7b2333-5578-40cd-940e-28e97d1b0aa1", "parentId": "0", "content": "完全同意你的观点", "createAt": "2025-08-07T11:42:43.526" }, { "id": "0b1d0cbd-62a7-4922-b5fe-0ef4780e4c24", "parentId": "0", "content": "内容很实用", "createAt": "2025-08-07T15:42:43.526" } ] }, { "id": "1a0e5854-c748-4c6b-a11d-d5bbb58326a1", "title": "电影推荐合集", "content": "# 这是用户用户B的帖子内容\n包含丰富的文本内容...", "userId": "70ec5f9f-7e9b-4f57-b2a4-9a35a163bd3e", "publishAt": "2025-08-03T02:42:43.525", "userName": "70ec5f9f-7e9b-4f57-b2a4-9a35a163bd3e", "categoryNames": "教育,科技", "commentList": [ { "id": "723a588c-0d95-4db7-be6b-1745bfcfc540", "parentId": "0", "content": "内容很实用", "createAt": "2025-08-07T00:42:43.526" }, { "id": "116ab46b-9b61-4644-ac10-73e65f5a01b9", "parentId": "0", "content": "内容很实用", "createAt": "2025-08-07T18:42:43.526" }, { "id": "65cb0f86-7076-46a6-b333-c9c50e9336ae", "parentId": "0", "content": "写得真详细", "createAt": "2025-08-07T18:42:43.526" } ] } } ``` -------------------------------- ### BaseEntity Example Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/practice/apt/auto-props.md An example of a BaseEntity class with common fields like id, createTime, updateTime, etc. It includes a static field AUTO_PROPERTIES_IGNORE for convenience in excluding these fields. ```java @Data @FieldNameConstants public abstract class BaseEntity implements Serializable, Cloneable { private static final long serialVersionUID = -1L; /** * Record identifier;Record identifier */ @Column(primaryKey = true) private String id; /** * Create time;Create time */ @UpdateIgnore private LocalDateTime createTime; /** * Update time;Update time */ private LocalDateTime updateTime; /** * Creator;Creator */ @UpdateIgnore private String createBy; /** * Updater;Updater */ private String updateBy; /** * Is deleted;Is deleted * Where [strategyName = "DELETE_WITH_USER_TIME"] means the logical delete strategy uses a strategy named [DELETE_WITH_USER_TIME] * So you must register a logical delete named [DELETE_WITH_USER_TIME] when customizing */ @LogicDelete(strategy = LogicDeleteStrategyEnum.CUSTOM,strategyName = "DELETE_WITH_USER_TIME") @UpdateIgnore private Boolean deleted; /** * Deleter */ @UpdateIgnore private String deleteBy; /** * Delete time */ @UpdateIgnore private LocalDateTime deleteTime; public static final String AUTO_PROPERTIES_IGNORE = Fields.deleteBy + "," + Fields.deleted + "," + Fields.deleteTime + "," + Fields.updateBy + "," + Fields.updateTime; } ``` -------------------------------- ### Manual Batch Update Example Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/ability/batch.md Shows how to execute a manual batch update using the `batch()` method on an `updatable` query. Similar to inserts, be mindful of return value accuracy. ```java List users = getUsers(); // Manual batch update easyEntityQuery.updatable(users).batch().executeRows(); ``` -------------------------------- ### Java Stream API Grouping Example Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/ability/select/group.md Demonstrates grouping a list of Person objects by city using Java's Stream API. This is a basic example of data aggregation. ```java public class Person { private String name; private String city; // Constructor, getters & setters omitted } List people = Arrays.asList( new Person("a", "e"), new Person("b", "f"), new Person("c", "g"), new Person("d", "h") ); // Use Stream API for grouping Map> groupedPeople = people.stream() .collect(Collectors.groupingBy(Person::getCity)); // Output grouped result for (Map.Entry> entry : groupedPeople.entrySet()) { System.out.println("City: " + entry.getKey() + ", People: " + entry.getValue()); } ``` -------------------------------- ### Query Classes without Students whose Name Starts with '金' Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/demo/subquery.md Finds classes that have no students whose names start with '金'. This can be achieved using 'none' or by filtering with 'where' and then calling 'none'. ```java List list = easyEntityQuery.queryable(SchoolClass.class) .where(s -> { s.schoolStudents().none(stu -> { stu.name().likeMatchLeft("金"); }); }).toList(); ``` ```java List list = easyEntityQuery.queryable(SchoolClass.class) .where(s -> { s.schoolStudents().where(stu -> { stu.name().likeMatchLeft("金"); }).none(); }).toList(); ``` -------------------------------- ### Generating SQL with EasyQuery Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/ability/where.md Demonstrates how to use the queryable API to build and execute SQL queries based on the defined request object. This example shows setting various filter conditions and ordering. ```java import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; import com.mybatisflex.core.query.EasyQuery; import java.math.BigDecimal; import java.time.LocalDateTime; public class EasyQueryTest { @Test public void testBlogQuery() { EasyQuery easyQuery = new EasyQuery(); BlogQueryRequest blogQueryRequest = new BlogQueryRequest(); blogQueryRequest.setTitle("123"); blogQueryRequest.setTitle2("123"); blogQueryRequest.setTitle3("123"); blogQueryRequest.setContent("123"); blogQueryRequest.setStar(123); blogQueryRequest.setPublishTimeBegin(LocalDateTime.now()); blogQueryRequest.setPublishTimeEnd(LocalDateTime.now()); blogQueryRequest.setScore(new BigDecimal("123")); blogQueryRequest.setStatus(1); blogQueryRequest.setOrder(new BigDecimal("12")); blogQueryRequest.setIsTop(false); blogQueryRequest.getOrders().add("status"); blogQueryRequest.getOrders().add("score"); String sql = easyQuery.queryable(BlogEntity.class) .whereObject(true, blogQueryRequest) .orderByObject(true, blogQueryRequest) .toSQL(); // Note: The expected SQL string might need adjustment based on the exact EasyQuery version and configuration. // The provided expected SQL in the prompt has been slightly modified for clarity and common SQL syntax. String expectedSql = "SELECT `id`,`create_time`,`update_time`,`create_by`,`update_by`,`deleted`,`title`,`content`,`url`,`star`,`publish_time`,`score`,`status`,`order`,`is_top`,`top` FROM `t_blog` WHERE `deleted` = ? AND `title` LIKE ? AND (\`title\` LIKE ? OR \`content\` LIKE ?) AND (\`id\` = ? OR \`content\` = ?) AND `url` LIKE ? AND `star` = ? AND `publish_time` >= ? AND `publish_time` <= ? AND `score` >= ? AND `status` <= ? AND `order` > ? AND `is_top` <> ? ORDER BY `status` ASC,`score` ASC"; assertEquals(expectedSql, sql); } } ``` -------------------------------- ### OffsetChunk for Pagination Source: https://github.com/xuejmnet/easy-query-doc/blob/main/src/en/feature.md Demonstrates how to use offsetChunk for custom pagination logic. The first example offsets by the size of the current chunk, while the second example offsets by 0, effectively disabling further offsetting for that chunk. ```java easyEntityQuery.queryable(BlogEntity.class) .orderBy(b -> b.createTime().asc()) .orderBy(b -> b.id().asc()) .offsetChunk(3, chunk -> { for (BlogEntity blog : chunk.getValues()) { a.incrementAndGet(); } //The offset is the size of the results queried this time return chunk.offset(chunk.getValues().size()); }); easyEntityQuery.queryable(BlogEntity.class) .orderBy(b -> b.createTime().asc()) .orderBy(b -> b.id().asc()) .offsetChunk(100, chunk -> { for (BlogEntity blog : chunk.getValues()) { a.incrementAndGet(); } //Do not offset return chunk.offset(0); }); ```