{"id":35620856,"url":"https://github.com/xbatis/xbatis","last_synced_at":"2026-03-03T04:27:46.225Z","repository":{"id":241278082,"uuid":"804770458","full_name":"xbatis/xbatis","owner":"xbatis","description":"一款基于mybatis的ORM框架,非常强大，非常好用，不信的来试试，2024年超级优秀的ORM!!!","archived":false,"fork":false,"pushed_at":"2026-02-28T04:31:35.000Z","size":4874,"stargazers_count":126,"open_issues_count":0,"forks_count":11,"subscribers_count":2,"default_branch":"main","last_synced_at":"2026-02-28T10:07:49.766Z","etag":null,"topics":["database","dbutils","mybatis","mybatis-xbatis","orm","orm-framework","sql","xbatis","xbatis-java","xbatis-orm"],"latest_commit_sha":null,"homepage":"http://xbatis.cn","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xbatis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-05-23T08:31:36.000Z","updated_at":"2026-02-06T09:10:32.000Z","dependencies_parsed_at":"2025-08-04T03:13:35.675Z","dependency_job_id":"d4ada16b-d9e7-4c1d-aa74-63b3438ea25b","html_url":"https://github.com/xbatis/xbatis","commit_stats":null,"previous_names":["mybatis-mp/mybatis-mp","xbatis/xbatis"],"tags_count":35,"template":false,"template_full_name":null,"purl":"pkg:github/xbatis/xbatis","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xbatis%2Fxbatis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xbatis%2Fxbatis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xbatis%2Fxbatis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xbatis%2Fxbatis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xbatis","download_url":"https://codeload.github.com/xbatis/xbatis/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xbatis%2Fxbatis/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30031983,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-03T03:27:35.548Z","status":"ssl_error","status_checked_at":"2026-03-03T03:27:09.213Z","response_time":61,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","dbutils","mybatis","mybatis-xbatis","orm","orm-framework","sql","xbatis","xbatis-java","xbatis-orm"],"created_at":"2026-01-05T06:24:17.394Z","updated_at":"2026-03-03T04:27:46.218Z","avatar_url":"https://github.com/xbatis.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Xbatis AI Agent Knowledge Base\n\n\u003e Official site: https://xbatis.cn  \n\u003e DeepWiki documentation: https://deepwiki.com/xbatis/xbatis\n\nKnowledge pack for AI agents working with the Xbatis framework. It distills the official Chinese materials into a\nself-contained explanation so that automated assistants can understand the framework capabilities, common patterns, and\nkey APIs.\n\n# English | [简体中文](README.zh-CN.md)\n\n---\n\n## 1. Framework Overview\n\n- **Positioning**: Xbatis is built on MyBatis and delivers a highly ORM-like database experience, emphasizing \"less SQL,\n  fluent DSL, cross-database compatibility\".\n- **Primary advantages**:\n    - Multi-table joins, subqueries, fluent pagination, automatic SQL optimization (auto-removal of redundant\n      `LEFT JOIN` / `ORDER BY`, smarter `COUNT`).\n    - Built-in `RETURNING` support, batch insert/update chains, native function wrappers, SQL templates.\n    - Single mapper mode that allows one `BasicMapper` to cover every entity.\n    - Database function library, database-specific `dbAdapt`, dynamic datasource routing.\n    - Full annotation ecosystem: logical delete, multi-tenancy, optimistic locking, result mapping, condition mapping,\n      dynamic default value injection, etc.\n- **Core characteristics** (from the official highlights):\n    1. Extremely lightweight: only wraps MyBatis without invasive modification.\n    2. High performance: keeps execution efficiency close to handwritten SQL.\n    3. Flexible and easy to use: fluent APIs read like natural language.\n    4. Highly available: covers more than 90% of common SQL scenarios.\n    5. Reliable and safe: concise design yet feature-rich, hardened by extensive testing.\n    6. Pagination optimization: automatically tunes `JOIN`, `COUNT`, `ORDER BY`, and ships with a built-in pager.\n\n---\n\n## 2. Core Modules \u0026 Package Paths\n\n| Module             | Typical package                 | Core types                                                                                                                    | Purpose                                                            |\n|--------------------|---------------------------------|-------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|\n| Core Mapper        | `cn.xbatis.core.mybatis.mapper` | `MybatisMapper\u003cT\u003e`, `BasicMapper`                                                                                             | Provides base CRUD plus single-mapper capabilities                 |\n| Fluent DSL         | `cn.xbatis.core.chain`          | `QueryChain`, `InsertChain`, `UpdateChain`, `DeleteChain`                                                                     | Build complex SQL, batch ops, returning clauses                    |\n| Global config      | `cn.xbatis.core.config`         | `XbatisGlobalConfig`                                                                                                          | Unified naming rules, interceptors, dynamic values, paging         |\n| Annotation suite   | `cn.xbatis.db.annotations`      | `@Table`, `@TableId`, `@TableField`, `@LogicDelete`,`@LogicDeleteTime`, `@TenantId`, `@Version`, `@Condition`, `@Fetch`, etc. | Entity mapping, injection rules, condition objects, result shaping |\n| Database functions | `db.sql.api.impl.cmd`           | `Methods`                                                                                                                     | Cross-database functions, SQL templates, fluent wrappers           |\n| Multi-tenant       | `cn.xbatis.core.tenant`         | `TenantContext`, `TenantId`                                                                                                   | Register and propagate tenant IDs globally                         |\n| Dynamic datasource | `cn.xbatis.datasource.routing`  | `@DS`, `JdbcConfigDecryptor`                                                                                                  | Runtime datasource switching, encrypted configs, grouped routing   |\n| Logical delete     | `cn.xbatis.core.logic`          | `LogicDeleteSwitch`, `LogicDeleteUtil`                                                                                        | Toggle logical delete, easy overrides                              |\n| Dynamic values     | `cn.xbatis.core.dynamic`        | `XbatisGlobalConfig#setDynamicValue`                                                                                          | Define tokens like `{NOW}`, `{TODAY}`                              |\n| Code generation    | `cn.xbatis.codegen`             | `GeneratorConfig` and sub modules                                                                                             | One-stop generation for entities, mapper, service skeletons, etc.  |\n\n---\n\n## 3. Quick Start \u0026 Dependencies\n\n### 3.1 Maven coordinates example\n\n```xml\n\u003cdependencyManagement\u003e\n  \u003cdependencies\u003e\n    \u003cdependency\u003e\n      \u003cgroupId\u003ecn.xbatis\u003c/groupId\u003e\n      \u003cartifactId\u003exbatis-spring-boot-parent\u003c/artifactId\u003e\n      \u003cversion\u003e1.9.8\u003c/version\u003e\n      \u003ctype\u003epom\u003c/type\u003e\n      \u003cscope\u003eimport\u003c/scope\u003e\n    \u003c/dependency\u003e\n  \u003c/dependencies\u003e\n\u003c/dependencyManagement\u003e\n\n\u003cdependencies\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003ecn.xbatis\u003c/groupId\u003e\n    \u003cartifactId\u003exbatis-spring-boot3-starter\u003c/artifactId\u003e\n  \u003c/dependency\u003e\n\u003c/dependencies\u003e\n```\n\n### 3.2 Datasource configuration example\n\n```yaml\nspring:\n  datasource:\n    url: jdbc:mysql://localhost:3306/dbName\n    username: dbusername\n    password: dbpassword\n```\n\n### 3.3 Bootstrapping skeleton example\n\n```java\n@SpringBootApplication\n@MapperScan(\"com.xx.xxx.mapper\")\npublic class XbatisApplication {\n    public static void main(String[] args) {\n        SpringApplication.run(XbatisApplication.class, args);\n    }\n}\n```\n\n### 3.4 Spring Boot 2 integration\n\n- **Maven dependencies** (using `xbatis-spring-boot-starter`):\n  ```xml\n  \u003cdependencyManagement\u003e\n    \u003cdependencies\u003e\n      \u003cdependency\u003e\n        \u003cgroupId\u003ecn.xbatis\u003c/groupId\u003e\n        \u003cartifactId\u003exbatis-spring-boot-parent\u003c/artifactId\u003e\n        \u003cversion\u003e1.9.8\u003c/version\u003e\n        \u003ctype\u003epom\u003c/type\u003e\n        \u003cscope\u003eimport\u003c/scope\u003e\n      \u003c/dependency\u003e\n    \u003c/dependencies\u003e\n  \u003c/dependencyManagement\u003e\n\n  \u003cdependencies\u003e\n    \u003cdependency\u003e\n      \u003cgroupId\u003ecn.xbatis\u003c/groupId\u003e\n      \u003cartifactId\u003exbatis-spring-boot-starter\u003c/artifactId\u003e\n    \u003c/dependency\u003e\n  \u003c/dependencies\u003e\n  ```\n- **Datasource \u0026 mapper scanning**: same as 3.2/3.3; Spring Boot 2 continues to use `application.yml` and `@MapperScan`.\n- **Bootstrap class**: identical to 3.3, ensure the starter version matches Spring Boot 2.\n\n### 3.5 Solon integration\n\n- **Maven dependencies**:\n  ```xml\n  \u003c!-- Order matters: register Xbatis plugin before mybatis-solon-plugin --\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003ecn.xbatis\u003c/groupId\u003e\n    \u003cartifactId\u003exbatis-solon-plugin\u003c/artifactId\u003e\n    \u003cversion\u003e1.9.8\u003c/version\u003e\n  \u003c/dependency\u003e\n  \u003cdependency\u003e\n    \u003cgroupId\u003eorg.noear\u003c/groupId\u003e\n    \u003cartifactId\u003emybatis-solon-plugin\u003c/artifactId\u003e\n    \u003cversion\u003e${mybatis.solon.version}\u003c/version\u003e\n  \u003c/dependency\u003e\n  ```\n- **Configuration example**:\n  ```yaml\n  # solon.yml\n  ds:\n    schema: demo        # recommend matching the database name\n    jdbcUrl: jdbc:mysql://localhost:3306/demo?useUnicode=true\u0026characterEncoding=utf8\n    driverClassName: com.mysql.cj.jdbc.Driver\n    username: root\n    password: 123456\n\n  # Rule: mybatis.\u003cdatasource bean name\u003e\n  mybatis.master:\n    mappers:\n      - \"com.demo.mapper\"           # package scan\n      - \"classpath:mapper/**/*.xml\" # XML scan\n  ```\n- **Datasource bean**:\n  ```java\n  @Configuration\n  public class MybatisConfig {\n\n      @Bean(name = \"master\", typed = true)\n      public DataSource dataSource(@Inject(\"${ds}\") HikariDataSource ds) {\n          return ds;\n      }\n  }\n  ```\n- **Business usage**:\n  ```java\n  @Controller\n  public class DemoController {\n\n      @Db            // omit name for single datasource; specify @Db(\"master\") for multi-datasource\n      UserMapper mapper;\n\n      @Get\n      @Mapping(\"/test\")\n      public List\u003cUser\u003e test() {\n          return QueryChain.of(mapper)\n                  .like(User::getName, \"abc\")\n                  .list();\n      }\n  }\n  ```\n- Further configuration aligns with `mybatis-solon-plugin`; chaining DSL, sharding, and multi-tenancy remain available.\n  Entity, mapper, and service examples:\n\n```java\n@Data\n@Table\npublic class SysUser {\n    @TableId\n    private Integer id;\n    private String userName;\n    private String password;\n    private Integer roleId;\n    private LocalDateTime createTime;\n}\n\npublic interface SysUserMapper extends MybatisMapper\u003cSysUser\u003e {}\n\n@Service\npublic class TestService {\n    @Autowired\n    private SysUserMapper sysUserMapper;\n\n    public Pager\u003cSysUser\u003e demo() {\n        return QueryChain.of(sysUserMapper)\n                .eq(SysUser::getId, 1)\n                .like(SysUser::getUserName, \"xxx\")\n                .paging(Pager.of(1, 10));\n    }\n}\n\n\u003e Pager resides in `cn.xbatis.core.mybatis.mapper.context.Pager` and implements `cn.xbatis.page.IPager`. Common usage:\n\u003e - Static factories: `Pager.of(size)`, `Pager.of(number, size)`.\n\u003e - `setExecuteCount(boolean)`: control whether to run the count query.\n\u003e - `paging(Pager)`: pass into chain APIs and read `getResults()`, `getTotal()`, `getNumber()`, `getSize()`, `getTotalPage()`, etc.\n\u003e - `PagerGetSetUtil` enables dynamic read/write of extension fields by `PagerField`.\n```\n\n---\n\n## 4. Global Configuration `XbatisGlobalConfig` (`cn.xbatis.core.config.XbatisGlobalConfig`)\n\n- Configure ahead of time via Spring `ConfigurationCustomizer` or `@PostConstruct`.\n- Common methods:\n    - `setSingleMapperClass(MybatisBasicMapper.class)`: enable single-mapper mode with `BasicMapper`.\n    - `setTableUnderline(boolean)` / `setColumnUnderline(boolean)`: control table/column naming.\n    - `setDatabaseCaseRule(DatabaseCaseRule rule)` or `setDatabaseCaseRule(DbType, rule)`: adjust casing strategy.\n    - `setDynamicValue(\"{KEY}\", (clazz, type) -\u003e {...})` and `getDynamicValue(clazz, type, key)`: register and use\n      dynamic placeholders.\n    - `setLogicDeleteInterceptor((entity, update) -\u003e {...})` and `setLogicDeleteSwitch(boolean)`: standardize logical\n      delete metadata \u0026 toggles.\n    - `addMapperMethodInterceptor(new MyInterceptor())`, `enableInterceptOfficialMapperMethod()`: register custom mapper\n      interceptors, optionally extending official methods.\n    - `setPagingProcessor(DbType, PagingProcessor)`: customize pagination for each database.\n\n---\n\n## 5. Annotation Suite \u0026 Property Reference\n\n### 5.1 `@Table` (`cn.xbatis.db.annotations.Table`)\n\n| Property           | Nullable | Default                    | Description                                                               |\n|--------------------|----------|----------------------------|---------------------------------------------------------------------------|\n| `value`            | Yes      | –                          | Table name; defaults to camelCase-to-snake-case of entity name            |\n| `schema`           | Yes      | –                          | Database schema                                                           |\n| `columnNameRule`   | Yes      | `columnNameRule.IGNORE`    | Rule to derive column names when not specified                            |\n| `databaseCaseRule` | Yes      | `DatabaseCaseRule.DEFAULT` | Controls casing; works with `XbatisGlobalConfig.setDatabaseCaseRule(...)` |\n\nExample:\n\n```java\n@Table(databaseCaseRule = DatabaseCaseRule.UPPERCASE)\npublic class SysUser { }\n```\n\n### 5.2 `@TableId` (`cn.xbatis.db.annotations.TableId`)\n\n| Property        | Nullable | Default           | Description                                                          |\n|-----------------|----------|-------------------|----------------------------------------------------------------------|\n| `value`         | Yes      | `IdAutoType.AUTO` | Primary key strategy: `AUTO`, `NONE`, `SQL`, `GENERATOR`             |\n| `dbType`        | Yes      | –                 | Target database type for differentiating strategies                  |\n| `sql`           | Yes      | –                 | Required when `value = SQL`; custom SQL for ID retrieval             |\n| `generator` | Yes      | –                 | Required when `value = GENERATOR`; refers to registered ID generator |\n\nRepeatable to accommodate multiple database strategies.\n\n### 5.3 `@TableField` (`cn.xbatis.db.annotations.TableField`)\n\n| Property                       | Nullable | Default | Description                                                                                                             |\n|--------------------------------|----------|---------|-------------------------------------------------------------------------------------------------------------------------|\n| `value`                        | Yes      | –       | Column name; can be omitted when camelCase-to-snake-case applies                                                        |\n| `select`                       | Yes      | `true`  | Whether to participate when calling `select(Entity.class)`                                                              |\n| `insert`                       | Yes      | `true`  | Whether to write during `save`                                                                                          |\n| `update`                       | Yes      | `true`  | Does it update when updating? It will update when forced                                                                |\n| `neverUpdate`                  | Yes      | `false` | Never update, unless specified with Updating Chain, it will only be updated, and it will not be forced to update either |\n| `jdbcType`                     | Yes      | –       | Explicit JDBC type                                                                                                      |\n| `typeHandler`                  | Yes      | –       | Custom type handler                                                                                                     |\n| `defaultValue`                 | Yes      | –       | Insert default; supports static values and dynamic tokens like `{NOW}`                                                  |\n| `updateDefaultValue`           | Yes      | –       | Default during updates                                                                                                  |\n| `defaultValueFillAlways`       | Yes      | `false` | Always apply `defaultValue` on insert                                                                                   |\n| `updateDefaultValueFillAlways` | Yes      | `false` | Always apply `updateDefaultValue`                                                                                       |\n| `exists`                       | Yes      | `true`  | Whether the field physically exists (false for transient fields)                                                        |\n\n### 5.4 `@LogicDelete` (`cn.xbatis.db.annotations.LogicDelete`)\n\nLogical delete annotation.\n\n| Property      | Nullable | Default | Description                                                 |\n|---------------|----------|---------|-------------------------------------------------------------|\n| `beforeValue` | Yes      | –       | Value before deletion; null treated as `NULL`               |\n| `afterValue`  | No       | –       | Value after deletion; supports dynamic tokens `{NOW}`, etc. |\n\nCombine with `XbatisGlobalConfig.setLogicDeleteInterceptor` to fill deleter metadata.\n\n#### 5.4.2 `@LogicDeleteTime` (`cn.xbatis.db.annotations.LogicDeleteTime`)\n\nField name for logic delete timestamp; supports `LocalDateTime`, `Date`, `Long` (ms), `Integer` (seconds)\n\n### 5.5 `@TenantId` (`cn.xbatis.db.annotations.TenantId`)\n\nNo extra properties. Marks tenant ID fields; automatically filled on `save/update/delete` and appended to query\nconditions. Register tenant suppliers through `TenantContext.registerTenantGetter` (\n`cn.xbatis.core.tenant.TenantContext`).\n\n### 5.6 `@Version` (`cn.xbatis.db.annotations.Version`)\n\nNo extra properties. Marks optimistic-lock version fields. `save` sets it to 0; `update/delete` append\n`WHERE version = ?` and successful updates increment it automatically.\n\n### 5.7 Lifecycle annotations: `@OnInsert` (`cn.xbatis.db.annotations.OnInsert`), `@OnUpdate` (\n\n`cn.xbatis.db.annotations.OnUpdate`)\n\n| Annotation  | Property | Nullable | Default | Description                                                   |\n|-------------|----------|----------|---------|---------------------------------------------------------------|\n| `@OnInsert` | `value`  | Yes      | –       | Assign pre-insert listener implementing `OnInsertListener\u003cT\u003e` |\n| `@OnUpdate` | `value`  | Yes      | –       | Assign pre-update listener implementing `OnUpdateListener\u003cT\u003e` |\n\nBesides local listeners, register global handlers via `XbatisGlobalConfig.setGlobalOnInsertListener` /\n`setGlobalOnUpdateListener`.\n\n### 5.8 Result-mapping annotations (`@ResultEntity` / `@ResultField` / `@Fetch`, etc. under `cn.xbatis.db.annotations`)\n\n- `@ResultEntity`: declare VO ↔ entity mapping and auto-complete `SELECT` columns.\n- `@ResultField`:\n\n  | Property | Nullable | Default | Description |\n        | --- | --- | --- | --- |\n  | `value` | Yes | – | Column(s) mapped to the field; supports multi-column inputs |\n  | `jdbcType` | Yes | – | JDBC type |\n  | `typeHandler` | Yes | – | Custom type handler |\n\n- `@Fetch`:\n\n  | Property | Nullable | Default | Description |\n        | --- | --- | --- | --- |\n  | `column` | Yes | – | Matching column; alternate to `property`, takes precedence |\n  | `property` | No | – | Source entity property |\n  | `source` | No | – | Source entity type |\n  | `storey` | Yes | `-1` | Source hierarchy; autodetect by default |\n  | `target` | No | – | Target entity (to be fetched) |\n  | `targetProperty` | No | – | Target entity join column |\n  | `targetSelectProperty` | Yes | – | Selected columns or expressions |\n  | `middle` | No | – | Middle entity (join table) |\n  | `middleSourceProperty` | No | – | Middle entity column bound to source |\n  | `middleTargetProperty` | No | – | Middle entity column bound to target |\n  | `orderBy` | Yes | – | Order clause, e.g., `\"[{xx} desc]\"` or `\"field desc\"` |\n  | `multiValueErrorIgnore` | Yes | `false` | Ignore multi-row result when expecting 1-to-1 |\n  | `limit` | Yes | `0` | Limit result size; 0 = unlimited |\n  | `memoryLimit` | Yes | `false` | Apply limit in-memory with IN to reduce queries |\n  | `nullFillValue` | Yes | `null` | Default when result is empty |\n  | `otherConditions` | Yes | – | Extra conditions, e.g., `[{Type} = 2]` |\n\n- **AI generation tip**: prefer using `@ResultEntity` and the related annotations (`@ResultField`,\n  `@NestedResultEntity`, `@NestedResultEntityField`, `@ResultCalcField`, `@Fetch`, `@PutEnumValue`, `@PutValue`, etc.)\n  on VO/DTOs for direct return types, eliminating manual transformation. Do not annotate entities with these; keep\n  `@TypeHandler`, `@Put***` on result objects only to avoid polluting entity models.\n\n- `@NestedResultEntity` (`cn.xbatis.db.annotations.NestedResultEntity`):\n\n  | Property | Nullable | Default | Description |\n        | --- | --- | --- | --- |\n  | `target` | Yes | – | Target entity; defaults to `@ResultEntity` target |\n  | `storey` | Yes | `1` | Storage level; differentiate layers in self-joins |\n  Declaring VO fields as nested objects automatically fills nested results recursively.\n\n- `@NestedResultEntityField` (`cn.xbatis.db.annotations.NestedResultEntityField`):\n\n  | Property | Nullable | Default | Description |\n        | --- | --- | --- | --- |\n  | `value` | Yes | – | Field name inside the nested entity |\n  Use when VO field names differ from entity fields. Works well with Lombok `@FieldNameConstants`.\n\n- `@ResultCalcField` (`cn.xbatis.db.annotations.ResultCalcField`):\n\n  | Property | Nullable | Default | Description |\n        | --- | --- | --- | --- |\n  | `value` | No | – | Calculation SQL, e.g., `count(1)`, `sum({id})` |\n  | `target` | Yes | – | Target entity; defaults to `@ResultEntity` target |\n  | `storey` | Yes | `1` | Storage level |\n  When `select(VO.class)`, automatically produces aggregate columns. Use `{field}` placeholders for dynamic columns.\n\n- `@PutEnumValue` (`cn.xbatis.db.annotations.PutEnumValue`):\n\n  | Property | Nullable | Default | Description |\n        | --- | --- | --- | --- |\n  | `source` | No | – | Source entity |\n  | `property` | No | – | Field storing enum code |\n  | `storey` | Yes | `1` | Storage level |\n  | `target` | No | – | Enum class |\n  | `code` | No | `code` | Field name representing the code |\n  | `value` | No | `name` | Field name representing display value |\n  | `required` | No | `false` | Throw if enum not found |\n  | `defaultValue` | Yes | – | Fallback when enum missing |\n  Suitable for auto-converting status codes to labels; supports nested mappings and multi-column matching.\n\n- `@PutValue` (`cn.xbatis.db.annotations.PutValue`):\n\n  | Property | Nullable | Default | Description |\n        | --- | --- | --- | --- |\n  | `source` | No | – | Source entity |\n  | `property` | No | – | Source field |\n  | `storey` | Yes | `1` | Storage level |\n  | `factory` | No | – | Factory class providing static method |\n  | `method` | No | – | Method name inside factory |\n  | `required` | No | `false` | Throw if value missing |\n  | `defaultValue` | Yes | – | Default value |\n  Supports injecting dynamic values based on multiple fields. Results are cached per session using\n  `factory+method+args`.\n\nCombine these annotations: use `@ResultEntity` for overall mapping, `@NestedResultEntity` for nested structure,\n`@ResultCalcField` for aggregates, and `@PutEnumValue`/`@PutValue` for extra data—delivering near-entity auto-wiring for\nVOs.\n\n### 5.9 Sharding annotations (`@SplitTable`, `@SplitTableKey`, `TableSplitter` in `cn.xbatis.db.annotations`)\n\n- `@SplitTable`:\n\n  | Property | Nullable | Default | Description |\n        | --- | --- | --- | --- |\n  | `value` | No | – | `TableSplitter` implementation used to compute actual table name |\n\n- `@SplitTableKey`: marks the sharding key field; supports a single column and takes sharding input at runtime.\n\n`TableSplitter` interface methods:\n\n```java\nboolean support(Class\u003c?\u003e type);\nString split(String sourceTableName, Object splitValue);\n```\n\n`support` declares supported key types; `split` returns actual table names like `sys_user_0` ~ `sys_user_9`.\nQueries/updates must include the shard key so Xbatis can locate the table.\n\n### 5.10 Condition annotation combinations\n\n#### `@ConditionTarget` (`cn.xbatis.db.annotations.ConditionTarget`)\n\n| Property | Nullable | Default     | Description                                                    |\n|----------|----------|-------------|----------------------------------------------------------------|\n| `value`  | No       | –           | Target entity; defaults to current class if omitted            |\n| `logic`  | Yes      | `Logic.AND` | Default top-level logic; set to `Logic.OR` for OR combinations |\n\n#### `@Condition` (`cn.xbatis.db.annotations.Condition`)\n\n| Property       | Nullable | Default             | Description                                                          |\n|----------------|----------|---------------------|----------------------------------------------------------------------|\n| `value`        | Yes      | `Condition.Type.EQ` | Condition type, e.g., `LIKE`, `GT`, `BETWEEN`, `EXISTS`              |\n| `target`       | Yes      | –                   | Target entity; defaults to `@ConditionTarget` or current class       |\n| `property`     | Yes      | –                   | Target property name; defaults to field name                         |\n| `storey`       | Yes      | –                   | Source storage level for nested objects                              |\n| `likeMode`     | Yes      | –                   | `LEFT`, `RIGHT`, `BOTH`, etc.                                        |\n| `toEndDayTime` | Yes      | `false`             | Auto-extend to end of day for `LTE` or second parameter of `BETWEEN` |\n| `defaultValue` | Yes      | –                   | Static value or dynamic key `{NOW}`, `{TODAY}`, custom entries       |\n\n#### `@Conditions` (`cn.xbatis.db.annotations.Conditions`)\n\n| Property | Nullable | Default    | Description                                                           |\n|----------|----------|------------|-----------------------------------------------------------------------|\n| `value`  | Yes      | –          | Multiple `@Condition` elements, often for keyword multi-column search |\n| `logic`  | Yes      | `Logic.OR` | Logic among combined conditions                                       |\n\n#### `@ConditionGroup` (`cn.xbatis.db.annotations.ConditionGroup`)\n\n| Property | Nullable | Default     | Description                                 |\n|----------|----------|-------------|---------------------------------------------|\n| `value`  | Yes      | –           | Grouped fields                              |\n| `logic`  | Yes      | `Logic.AND` | Group logic; change to `Logic.OR` as needed |\n\nIf DTO implements `ObjectConditionLifeCycle` (`cn.xbatis.core.sql.ObjectConditionLifeCycle`), it can preprocess input in\n`beforeBuildCondition()` (e.g., derive past 7 days based on `timeType`) and cooperate with the annotations above for\ndeep nesting.\n\n---\n\n---\n\n## 6. Mapper Basic Capabilities\n\n`MybatisMapper\u003cT\u003e` (`cn.xbatis.core.mybatis.mapper.MybatisMapper`) ships with:\n\n- **Read**: `get`, `list`, `listAll`, `listByIds`, `cursor`, `exists`, `count`, `mapWithKey`, `page`, etc., accepting\n  lambda `Where` builders.\n- **Create**: `save`, `saveOrUpdate`, `saveBatch`, `saveModel`, `saveModelBatch`, `saveBatch(list, fields)`, supporting\n  entity and `Model`.\n- **Update**: `update`, `updateBatch`, `update(model, where)`, `update(list, forceFields)`, `saveOrUpdate`, plus forced\n  update fields and batch `CASE WHEN` updates.\n- **Delete**: `deleteById`, `deleteByIds`, `delete(entity)`, `delete(where)`, `deleteAll`, and `DeleteChain`.\n- **Single-mapper mode** (for large entity counts or unified data-access layers):\n    1. **Define your own MybatisBasicMapper interface extending BasicMapper**\n       ```java\n       public interface MybatisBasicMapper extends BasicMapper {\n       }\n       ```\n       `BasicMapper` lives in `cn.xbatis.core.mybatis.mapper.BasicMapper` and wraps all general CRUD.\n    2. **Configure scanning** (Spring Boot example)\n       ```java\n       @MapperScan(basePackageClasses = MybatisBasicMapper.class,\n                   markerInterface = BasicMapper.class)\n       ```\n       Generates a single mapper bean instead of one per entity.\n    3. **Register the global mapper**\n       Call `XbatisGlobalConfig.setSingleMapperClass(MybatisBasicMapper.class);` during startup to designate the default\n       entry.\n    4. **Usage pattern**\n       ```java\n       @Autowired\n       private MybatisBasicMapper mybatisBasicMapper;\n  \n       public void demo() {\n           // Entity CRUD\n           mybatisBasicMapper.save(new SysUser());\n           mybatisBasicMapper.deleteById(SysUser.class, 1);\n  \n           // Fluent DSL: explicitly pass entity class\n           QueryChain.of(mybatisBasicMapper, SysUser.class)\n                   .eq(SysUser::getId, 1)\n                   .list();\n           UpdateChain.of(mybatisBasicMapper, SysUser.class)\n                   .set(SysUser::getUserName, \"basic\")\n                   .eq(SysUser::getId, 1)\n                   .execute();\n       }\n       ```\n       Combine with `BasicDaoImpl` (`cn.xbatis.core.mvc.impl.BasicDaoImpl`) to keep a classic three-layer architecture.\n    5. **Handling complex SQL**\n       Single mapper still cooperates with XML using namespace `xxx.MybatisBasicMapper` and `withSqlSession`:\n       ```java\n       List\u003cSysRole\u003e roles = mybatisBasicMapper.withSqlSession(\n           SysRole.class,\n           \"selectByIds\",\n           params,\n           (statement, p, sqlSession) -\u003e sqlSession.selectList(statement, p)\n       );\n       ```\n    6. **Notes**\n\n    - DSL requires explicit entity class to resolve table/columns.\n    - You can keep traditional mappers alongside single mapper, but maintain consistent conventions.\n    - XML `\u003cselect id=\"EntityName:method\"\u003e` naming must align with `withSqlSession` calls.\n\n---\n\n### 6.1 Insert/batch insert conflict handling\n\nXbatis `save` / `saveBatch` / `InsertChain` support cross-database duplicate-key strategies (ignore or update on\nconflict).\n\n| Database   | Ignore on conflict | Update on conflict |\n|------------|--------------------|--------------------|\n| MySQL      | ✅                  | ✅                  |\n| MariaDB    | ✅                  | ✅                  |\n| Oracle     | ✅                  | ❌                  |\n| H2         | ✅                  | ✅                  |\n| PostgreSQL | ✅                  | ✅                  |\n| Kingbase   | ✅                  | ✅                  |\n| SQLite     | ✅                  | ✅                  |\n| openGauss  | ✅                  | ✅                  |\n\n`onConflict` lives in `cn.xbatis.core.mybatis.mapper.context.strategy.SaveStrategy` / `SaveBatchStrategy` and the chain\nSQL interface `db.sql.api.cmd.executor.IInsert`, building portable statements via `IConflictAction`.\n\n#### Single insert\n\n```java\nMultiPk entity = new MultiPk();\nentity.setId1(1);\nentity.setId2(2);\nentity.setName(\"init\");\n\nmapper.save(entity, strategy -\u003e {\n    strategy.onConflict(action -\u003e action.doNothing()); // ignore\n    // or update on conflict (overwrite all fields)\n    // strategy.onConflict(action -\u003e action.doUpdate(update -\u003e update.overwriteAll()));\n});\n```\n\n#### Multiple inserts\n\n```java\nList\u003cMultiPk\u003e list = List.of(entity1, entity2);\n\n// mapper.save(List\u003cT\u003e, ...)\nmapper.save(list, strategy -\u003e\n        strategy.onConflict(action -\u003e action.doUpdate(update -\u003e update.overwrite(MultiPk::getName)))\n);\n\n// mapper.saveBatch(List\u003cT\u003e, ...)\nmapper.saveBatch(list, strategy -\u003e\n        strategy.onConflict(action -\u003e action.doNothing())\n);\n```\n\n`overwriteAll()` updates every column; `overwrite(Entity::getField)` targets specific columns.\n\n#### InsertChain conflict strategy\n\n```java\nInsertChain.of(sysUserMapper)\n    .insert(SysUser.class)\n    .values(Arrays.asList(\"basic\", \"123456\"))\n    .onConflict(action -\u003e action.doUpdate(update -\u003e update.overwrite(SysUser::getPassword)))\n    .execute();\n```\n\nUse `dbAdapt` inside the strategy for database-specific tuning.\n\n---\n\n## 7. Fluent DSL\n\n### 7.1 QueryChain\n\n`cn.xbatis.core.chain.QueryChain` constructs combinations of `select`, `from`, `join`, `where`, `groupBy`, `having`,\n`orderBy`, pagination, nested conditions, and subqueries.\n\n- **AI generation tip**: default to Xbatis condition helpers such as `.forSearch(true)` or\n  `eq(field, value, predicate)` / `eq(boolean, field, value)` instead of manual `if/else` on `WHERE` clauses to keep\n  code tidy and robust.\n\nExample:\n\n```java\nSysUserRoleVo vo = QueryChain.of(sysUserMapper)\n    .select(SysUser.class, SysRole.class)\n    .from(SysUser.class)\n    .join(SysUser::getRoleId, SysRole::getId)\n    .eq(SysUser::getId, 1)\n    .like(SysUser::getUserName, \"abc\")\n    .groupBy(SysUser::getId)\n    .having(SysUser::getId, c -\u003e c.count().gt(0))\n    .orderBy(SysUser::getId)\n    .returnType(SysUserRoleVo.class)\n    .get();\n```\n\nKey capabilities:\n\n- `select` accepts entities, VO classes, lambda fields, function wrappers, ignored columns.\n- `join` supports `inner`, `left`, `right`; leverage `@ForeignKey` for automatic join conditions.\n- `andNested` / `orNested` add parentheses; `and()` / `or()` control subsequent logic.\n- Condition methods include `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `between`, `notBetween`, `in`, `notIn`, `like`,\n  `notLike`, `isNull`, `isNotNull`, `empty`, `notEmpty`, `exists`, `notExists`. Each accepts a predicate argument for\n  conditional inclusion (e.g., `eq(SysUser::getId, id, Objects::nonNull)`). Global toggles include\n  `.ignoreNullValueInCondition(true)`, `.ignoreEmptyInCondition(true)`.\n- `forSearch(true)` simultaneously ignores null/blank values and trims strings—ideal for search forms.\n- `returnType(...)` is recommended right before terminal operations, after conditions/limits.\n- `where(queryObject)` converts annotated DTO fields into conditions.\n- `dbAdapt(selector -\u003e ...)` builds DB-specific behavior.\n- Terminal APIs: `get`, `list`, `count`, `exists`, `paging(Pager)`, `cursor`, `mapWithKey`.\n\n### 7.2 InsertChain\n\n`cn.xbatis.core.chain.InsertChain` supports `INSERT ... VALUES` and `INSERT ... SELECT` combos:\n\n```java\nInsertChain.of(sysUserMapper)\n    .insert(SysUser.class)\n    .fields(SysUser::getUserName, SysUser::getRoleId)\n    .fromSelect(Query.create()\n        .select(SysUser2::getUserName, SysUser2::getRoleId)\n        .from(SysUser2.class)\n    )\n    .execute();\n```\n\nAdd `values` repeatedly for batch inserts.\n\n### 7.3 UpdateChain\n\n`cn.xbatis.core.chain.UpdateChain` enables dynamic `set`, arithmetic updates, `RETURNING`, nested conditions:\n\n```java\nSysUser user = UpdateChain.of(sysUserMapper)\n    .update(SysUser.class)\n    .set(SysUser::getUserName, \"new name\")\n    .set(SysUser::getVersion, c -\u003e c.plus(1))\n    .eq(SysUser::getId, 1)\n    .returning(SysUser.class)\n    .returnType(SysUser.class)\n    .executeAndReturning();\n```\n\n### 7.4 DeleteChain\n\n`cn.xbatis.core.chain.DeleteChain` builds delete conditions and can return affected entities:\n\n```java\nList\u003cSysUser\u003e removed = DeleteChain.of(sysUserMapper)\n    .in(SysUser::getId, 1, 2)\n    .returning(SysUser.class)\n    .returnType(SysUser.class)\n    .executeAndReturningList();\n```\n\n---\n\n## 8. Object-driven Conditions \u0026 Sorting\n\n- Mark DTOs with `@ConditionTarget`.\n- Use `@Condition` for EQ, NE, GT, LT, BETWEEN, EXISTS, LIKE, etc., specifying target property, defaults,\n  `toEndDayTime`, `likeMode`.\n- `@Conditions` maps a single field to multiple columns with AND/OR control.\n- `@ConditionGroup` groups and nests logic.\n- Implement `ObjectConditionLifeCycle` for preprocessing (e.g., deriving date ranges from enums) before building\n  conditions.\n- Sorting uses similar patterns via condition annotations and helper utilities.\n\nExample:\n\n```java\n@Data\n@ConditionTarget(SysUser.class)\npublic class QueryREQ {\n    private Integer id;\n\n    @Condition(value = Condition.Type.LIKE)\n    private String userName;\n\n    @Conditions(\n        logic = Logic.OR,\n        value = {\n            @Condition(property = SysUser.Fields.userName, value = Condition.Type.LIKE),\n            @Condition(property = SysUser.Fields.password, value = Condition.Type.LIKE)\n        }\n    )\n    private String keyword;\n}\n```\n\n---\n\n## 9. Database Functions \u0026 SQL Templates\n\n- Import `import static db.sql.api.impl.cmd.Methods.*;` for unified functions.\n- Supported functions include `count`, `sum`, `avg`, `min`, `max`, `abs`, `ceil`, `floor`, `rand`, `sign`, `pi`,\n  `truncate`, `round`, `pow`, `sqrt`, `exp`, `mod`, `log`, `sin`, `cos`, `tan`, `charLength`, `concat`, `upper`,\n  `lower`, `substring`, `currentDate`, `dateDiff`, `dateAdd`, `inetAton`, plus MySQL-specific `findInSet`, `md5`,\n  `jsonExtract`, `groupConcat`, etc.\n- SQL template system:\n    - `Methods.tpl` – general SQL template with placeholders `{0}`, `{1}`.\n    - `Methods.fTpl` – function template, chainable with other functions.\n    - `Methods.cTpl` – condition template for complex `WHERE` fragments.\n    - Templates auto-escape single quotes; use `Methods.cTpl(true, \"...\", ...)` for automatic `'` handling.\n\nExample:\n\n```java\nQueryChain.of(sysUserMapper)\n    .select(SysUser::getRoleId, c -\u003e Methods.tpl(\"count({0})+{1}\", c, \"1\"))\n    .and(GetterFields.of(SysUser::getId, SysUser::getId),\n         cs -\u003e Methods.cTpl(\"{0}+{1}={2}\", cs[0], cs[1], 2));\n```\n\n---\n\n## 10. Multi-database \u0026 Dynamic Datasource\n\n### 10.1 Database differentiation\n\n- `QueryChain`, `UpdateChain`, `DeleteChain`, `InsertChain` all support `dbAdapt`:\n\n```java\nQueryChain.of(sysUserMapper)\n    .select(SysUser::getId)\n    .dbAdapt((query, selector) -\u003e selector\n        .when(DbType.H2, db -\u003e query.eq(SysUser::getId, 3))\n        .when(DbType.MYSQL, db -\u003e query.eq(SysUser::getId, 2))\n        .otherwise(db -\u003e query.eq(SysUser::getId, 1))\n    )\n    .get();\n```\n\n- You can also call `mapper.dbAdapt(selector -\u003e {...})` for entirely different flows.\n\n### 10.2 Dynamic datasource routing\n\n- Add `cn.xbatis:xbatis-datasource-routing`.\n- Configure `spring.ds.routing.*` for multiple datasources, master-slave, replica groups, and pool properties (supports\n  Hikari, Druid, custom).\n- Annotate classes/methods with `@DS(\"master\")`, `@DS(\"slave\")` to switch datasource.\n- Notes:\n    - Transaction propagation: use `@Transactional(propagation = Propagation.NOT_SUPPORTED)` or `REQUIRES_NEW` when\n      switching datasources mid-call.\n    - For self-invocation within same class, use `AopContext.currentProxy()` or split the class.\n    - `spring.ds.jdbc-config-decrypt=true` with `JdbcConfigDecryptor` enables encrypted JDBC configs.\n    - Supports distributed transaction frameworks like Seata (`spring.ds.seata=true`).\n\n---\n\n## 11. Multi-tenancy, Logical Delete, Optimistic Locking\n\n### 11.1 Multi-tenancy\n\n- Annotate entity fields with `@TenantId`; automatically fills tenant ID on write and appends conditions for\n  query/update/delete.\n- Register tenant suppliers via `TenantContext.registerTenantGetter(() -\u003e tenantId)` (\n  `cn.xbatis.core.tenant.TenantContext`), returning a single ID or `TenantId` (multi-tenant set).\n- Return `null` from supplier to temporarily disable tenant enforcement.\n- ThreadLocal usage: wrap helper like `TenantTLUtil` to set/clear tenants in filters/interceptors and return via\n  `TenantContext`.\n\n### 11.2 Logical delete\n\n- `@LogicDelete(beforeValue = \"0\", afterValue = \"1\")` controls before/after markers and timestamp.\n- `@LogicDeleteTime` controls logic delete time markers\n- `XbatisGlobalConfig.setLogicDeleteInterceptor` can fill deleter info automatically.\n- Toggle globally via `setLogicDeleteSwitch(true/false)`; locally via:\n\n```java\ntry (LogicDeleteSwitch ignored = LogicDeleteSwitch.with(false)) {\n    mapper.getById(1);\n}\n// or\nLogicDeleteUtil.execute(false, () -\u003e mapper.getById(1));\n```\n\n- Note: `DeleteChain` performs physical delete; only mapper delete methods respect logical delete.\n\n### 11.3 Optimistic lock\n\n- `@Version` fields default to 0 on `save`.\n- `update` / `delete` append `WHERE version=?`; updates increment version on success.\n\n### 11.4 Table sharding (SplitTable)\n\n- Annotate entity with `@SplitTable(TableSplitterClass.class)`; `value` points to `TableSplitter` implementation.\n- Annotate sharding key with `@SplitTableKey`; only single-column sharding is supported.\n- `TableSplitter#support(Class\u003c?\u003e)` declares supported key types; `split(String, Object)` returns real table name (e.g.,\n  `sys_user_3`).\n- Chains behave like regular entities, but queries must include sharding key conditions to resolve actual tables.\n- Works seamlessly with multi-db, tenant, logical delete, etc.\n\n---\n\n## 12. Dynamic Defaults \u0026 Event Listeners\n\n- Built-in tokens: `{BLANK}`, `{NOW}` (supports `LocalDateTime`, `LocalDate`, `Date`, `Long`, `Integer`, `String`),\n  `{TODAY}` (date range).\n- Custom dynamic example:\n\n```java\nXbatisGlobalConfig.setDynamicValue(\"{day7}\", (clazz, type) -\u003e new LocalDate[]{\n    LocalDate.now().minusDays(7), LocalDate.now()\n});\n```\n\n- Fetch dynamic value inside condition objects via\n  `XbatisGlobalConfig.getDynamicValue(clazz, LocalDate[].class, \"{day7}\")`.\n- Global listeners:\n\n```java\nXbatisGlobalConfig.setGlobalOnInsertListener(entity -\u003e {\n    // fill creator, etc.\n});\nXbatisGlobalConfig.setGlobalOnUpdateListener(entity -\u003e {\n    // fill updater, etc.\n});\n```\n\n---\n\n## 13. SQL Templates \u0026 XML Integration\n\n- Template mechanism enables reusable SQL fragments, function wrappers, condition composition without string splicing.\n- Fully compatible with traditional MyBatis XML; use naming conventions in single-mapper mode:\n\n```xml\n\u003cmapper namespace=\"xxx.MybatisBasicMapper\"\u003e\n  \u003cselect id=\"SysRole:selectByIds\" resultType=\"com.xbatis.core.test.DO.SysRole\"\u003e\n    select * from t_sys_role\n    where id \u003e= #{id} and id \u003c= #{id2}\n    order by id asc\n  \u003c/select\u003e\n\u003c/mapper\u003e\n```\n\nInvocation:\n\n```java\nList\u003cSysRole\u003e roleList = mybatisBasicMapper.withSqlSession(\n    SysRole.class, \"selectByIds\", params,\n    (statement, p, sqlSession) -\u003e sqlSession.selectList(statement, p)\n);\n```\n\n- XML works alongside chain DSL: call templates within chains or pass dynamic params from XML as needed.\n\n---\n\n## 14. Pagination \u0026 Performance Tuning\n\n- Built-in `Pager` handles pagination: `Pager.of(current, size)`, `QueryChain.paging(pager)` automatically executes\n  query + count.\n- Xbatis auto-optimizes pagination SQL: removes unnecessary `LEFT JOIN`, `ORDER BY`, replaces `SELECT` with `COUNT(*)`\n  to improve speed.\n- Customize via `XbatisGlobalConfig.setPagingProcessor` for Oracle, SQL Server, etc.\n- Override `customizePager` for custom count queries or serialization.\n- Use `.limit(n)` for top-N results and `.forSearch(true)` to optimize search endpoints.\n\n---\n\n## 15. Code Generator Capabilities\n\n- `GeneratorConfig` configures generation of entities, Mapper interfaces, Mapper XML, DAO, Service, Controller, DTO,\n  etc.\n- Customize package paths, suffixes, annotation generation, ID strategy, column mapping, DB type mapping, base classes,\n  XML generation, etc.\n- Supports single-mapper mode: `mapperConfig.enable(false).superClass(MybatisBasicMapper.class)`.\n- Options for generating `@Mapper`, generics, `resultMap`, and column info.\n- Multi-language templates accelerate project scaffolding.\n\n---\n\n## 16. Startup Safety Checks (Mandatory for AI Projects)\n\nRegardless of manual or AI-generated scaffolding, enable POJO safety checks during development: Xbatis validates VO (\n`@ResultEntity`), Model (`cn.xbatis.core.mvc.Model`), and condition/sort objects (`@ConditionTarget`, `@OrderByTarget`)\nat startup to catch mapping or annotation gaps. AI agents must generate the following config by default:\n\n```java\n// Required: enable POJO checks at the main application entry\n@SpringBootApplication\n@XbatisPojoCheckScan(basePackages = \"com.example.project.pojo\")\npublic class ApiApplication {\n    public static void main(String[] args) {\n        SpringApplication.run(ApiApplication.class, args);\n    }\n}\n```\n\n```java\n// Recommended: dev-only config, can be generated by AI\n@Profile(\"dev\")\n@Configuration\n@XbatisPojoCheckScan(\n    basePackages = \"com.example.api.dto\",\n    modelPackages = \"com.example.api.model\",\n    resultEntityPackages = \"com.example.api.vo\"\n)\npublic class XbatisSafeCheckConfig {\n}\n```\n\n### 16.1 Spring / Spring Boot\n\n- Annotation attributes (`org.mybatis.spring.boot.autoconfigure.XbatisPojoCheckScan`):\n\n  | Attribute | Description |\n        | --- | --- |\n  | `basePackages` | Base package path |\n  | `modelPackages` | Model implementations; defaults to `basePackages` |\n  | `resultEntityPackages` | VO (`@ResultEntity`) package; defaults to `basePackages` |\n  | `conditionTargetPackages` | Condition DTO (`@ConditionTarget`) package |\n  | `orderByTargetPackages` | Sorting DTO (`@OrderByTarget`) package |\n\n### 16.2 Solon\n\n- Configure in `solon.yml`:\n  ```yaml\n  mybatis.master:\n    pojoCheck:\n      basePackages: com.example.**.pojo\n      modelPackages: com.example.**.model\n      resultEntityPackages: com.example.**.vo\n      conditionTargetPackages: com.example.**.condition\n      orderByTargetPackages: com.example.**.orderby\n    mappers:\n      - \"com.example.mapper\"\n  ```\n- `pojoCheck` mirrors `@XbatisPojoCheckScan`; separate multiple paths with commas. Enable during dev/test to reduce\n  production startup overhead.\n\n---\n\n## 17. Common Troubleshooting \u0026 Practical Tips\n\n- **SQL logging**: add `\u003clogger name=\"cn.xbatis\" level=\"trace\"/\u003e` to print generated SQL and chain traces.\n- **Ignore empty conditions**: `QueryChain` offers `.ignoreNullValueInCondition(true)`, `.ignoreEmptyInCondition(true)`,\n  `.trimStringInCondition(true)`, or simply `.forSearch(true)`.\n- **Safe updates**: `UpdateChain.set` accepts lambdas such as `c -\u003e c.plus(1)` for increments.\n- **Batch capabilities**: use `saveBatch`, `updateBatch`, `InsertChain.values`, or the `batchOpt` module for efficient\n  batch handling.\n- **Enum \u0026 dictionary mapping**: `@PutEnumValue` injects enum labels; `@ResultField` handles field-level mapping;\n  `@Fetch` automates cascading queries.\n- **SQL template gotchas**: if single quotes cause problems, enable protected templates or switch to double quotes.\n- **Datasource switching under transactions**: mind transaction propagation when calling across datasources to avoid\n  Spring proxies blocking switches.\n\n---\n\n## 17. Practical Advice for AI Agents\n\n- **Retrieval strategy**: prioritize `QueryChain`, `InsertChain`, `UpdateChain`, `DeleteChain` plus annotations to cover\n  most CRUD/statistics tasks.\n- **Code generation tips**:\n    - Always use method references (e.g., `SysUser::getId`) instead of hard-coded column names.\n    - Search endpoints should call `.forSearch(true)` or rely on annotated DTOs to avoid manual null checks.\n    - For multi-database scenarios, add `dbAdapt`; multi-tenant scenarios should wire `TenantContext` automatically.\n    - When updates/deletes must return values, use `.executeAndReturning()` or `.executeAndReturningList()`.\n- **Project structure tips**:\n    - Single-mapper mode suits large projects; combine `BasicMapper` with DSL for unified data access.\n    - Document dynamic datasource, tenant, and logical delete switches explicitly in generated code.\n    - Use `GeneratorConfig` for initial scaffolding, then have the agent generate incremental chains/service logic.\n- **Security \u0026 auditing**: leverage `@OnInsert`, `@OnUpdate`, logical delete interceptors, tenant context to auto-fill\n  creator/update/tenant fields and satisfy audit requirements.\n\n---\n\n## Appendix: Productivity Cheatsheet (from `fast-dev.md`, essential for AI projects)\n\n### Specify database type\n\nSet `databaseId` explicitly to avoid detection overhead:\n\n```yaml\nmybatis:\n  configuration:\n    databaseId: MYSQL   # see db-support.md for available IDs\n```\n\n### Fluent API shorthand (AI-generated code should apply)\n\n- When query, `from`, and `returnType` all target the mapper entity, omit them:\n\n```java\nSysUser user = QueryChain.of(sysUserMapper)\n        .eq(SysUser::getId, 1)\n        .get();\n```\n\n- If `select(VO.class)` equals `returnType(VO.class)`, just call `returnType`; the framework auto-selects columns based\n  on VO annotations.\n\n- Bulk ignore: `.forSearch(true)` enables ignore-null/blank and auto-trim; use it by default.\n- Precise ignore:\n\n```java\nQueryChain.of(sysUserMapper)\n    .eq(SysUser::getId, id, Objects::nonNull)\n    .like(SysUser::getUserName, userName, StringUtils::isNotBlank)\n    .get();\n```\n\n### VO auto-mapping\n\n- Combine `@ResultEntity` + `@NestedResultEntity` for nested structures; omit attributes when VO fields match entity\n  fields.\n- Recommend using Lombok `@FieldNameConstants` and referencing `X.Fields.xxx` in annotations to avoid string literals.\n\n### Using `connect`\n\n`connect` exposes the chain itself for correlated subqueries:\n\n```java\nQueryChain.of(sysUserMapper)\n    .select(SysUser::getId, SysUser::getUserName)\n    .connect(query -\u003e query.exists(SubQuery.create()\n        .select1()\n        .from(SysUser.class)\n        .eq(SysUser::getId, query.$(SysUser::getId))\n        .isNotNull(SysUser::getPassword)\n        .limit(1)))\n    .list();\n```\n\n### Recommended function invocation style\n\nStatic-import `db.sql.api.impl.cmd.Methods.*` for concise chains:\n\n```java\nInteger id = QueryChain.of(sysUserMapper)\n        .select(SysUser::getId, c -\u003e sum(add(c, 1)))\n        .returnType(Integer.TYPE)\n        .get();\n```\n\nThese convenience patterns greatly enhance productivity and should be default assumptions when designing AI generation\nstrategies.\n\n---\n\nBundle this knowledge base with project source code and dependency API docs to build a vector store so AI agents can\ngenerate Xbatis-compliant code and configuration accurately.***\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxbatis%2Fxbatis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxbatis%2Fxbatis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxbatis%2Fxbatis/lists"}