{"id":48904585,"url":"https://github.com/myacelw/mybatis-dynamic","last_synced_at":"2026-04-19T10:01:14.726Z","repository":{"id":336067400,"uuid":"1133389474","full_name":"myacelw/mybatis-dynamic","owner":"myacelw","description":"Code-first ORM for Spring Boot. Zero XML, Auto DDL \u0026 Fluent Join API. Define your schema in Java and enjoy dynamic SQL power.","archived":false,"fork":false,"pushed_at":"2026-02-10T03:25:16.000Z","size":1963,"stargazers_count":1,"open_issues_count":2,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-02-10T07:35:24.705Z","etag":null,"topics":["code-generator","database","dynamic-sql","java","mybatis","orm","spring-boot"],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/myacelw.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":null,"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":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-01-13T09:28:20.000Z","updated_at":"2026-02-10T03:25:20.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/myacelw/mybatis-dynamic","commit_stats":null,"previous_names":["myacelw/mybatis-dynamic"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/myacelw/mybatis-dynamic","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/myacelw%2Fmybatis-dynamic","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/myacelw%2Fmybatis-dynamic/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/myacelw%2Fmybatis-dynamic/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/myacelw%2Fmybatis-dynamic/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/myacelw","download_url":"https://codeload.github.com/myacelw/mybatis-dynamic/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/myacelw%2Fmybatis-dynamic/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32002361,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"online","status_checked_at":"2026-04-19T02:00:07.110Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["code-generator","database","dynamic-sql","java","mybatis","orm","spring-boot"],"created_at":"2026-04-16T19:00:43.473Z","updated_at":"2026-04-19T10:01:14.720Z","avatar_url":"https://github.com/myacelw.png","language":"Java","funding_links":[],"categories":["Projects"],"sub_categories":["ORM"],"readme":"# mybatis-dynamic\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"logo.svg\" alt=\"mybatis-dynamic logo\" width=\"200\" height=\"200\"\u003e\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n    \u003cb\u003e\u003ca href=\"https://myacelw.github.io/mybatis-dynamic/\"\u003e📚 Official Documentation\u003c/a\u003e\u003c/b\u003e\n    \u003cbr\u003e\n    \u003cbr\u003e\n    \u003ca href=\"README.md\"\u003eEnglish README\u003c/a\u003e | \u003ca href=\"README_CN.md\"\u003e中文 README\u003c/a\u003e\n\u003c/p\u003e\n\n[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)\n[![Maven Central](https://img.shields.io/maven-central/v/io.github.myacelw/mybatis-dynamic-core.svg)](https://search.maven.org/search?q=g:io.github.myacelw%20AND%20a:mybatis-dynamic-core)\n\n**mybatis-dynamic** is a powerful dynamic ORM framework built on top of MyBatis. It allows developers to define data models directly in Java code, automatically managing the database schema (tables, columns, indexes) and providing a rich, fluent API for CRUD operations and complex queries.\n\n## Getting Started\n\n### Key Features\n\n- **Dynamic Modeling**: Define data models as Java classes. The framework automatically generates and updates the database schema (DDL) at startup or runtime.\n- **Runtime Model Modification**: Models can be modified programmatically at runtime, enabling dynamic business requirements.\n- **Rich Fluent API**: Construct complex queries with a natural, readable syntax. Supports automatic logical precedence (`AND` \u003e `OR`), nested grouping, and joins.\n- **Spring Boot Integration**: Seamless integration with Spring Boot. Simply annotate your model, and the framework auto-configures `BaseDao` and `BaseService` beans.\n- **Advanced Mapping**: Supports `@ToOne`, `@ToMany`, and recursive relationships.\n- **Visualisation**: Built-in tool to visualize model relationships.\n\n### Architecture\n\nThe project is modularized to separate concerns:\n\n- **`core`**: The engine. Handles dynamic modeling, SQL generation, and query execution. Can be used standalone.\n- **`spring`**: Spring Boot starter. Provides auto-configuration and easy integration.\n- **`draw`**: Visualization module. Provides a web UI to view entity relationships.\n- **`sample`**: A complete Spring Boot sample application demonstrating usage.\n\n### Installation \u0026 Configuration\n\n#### 1. Requirements\n\n- Java 8+\n- Maven or Gradle\n- A supported database (H2, MySQL, PostgreSQL, Oracle, OceanBase, etc.)\n\n#### 2. Add Dependency\n\nAdd the `mybatis-dynamic-spring` dependency to your project.\n\n**Maven:**\n\n```xml\n\u003cdependency\u003e\n    \u003cgroupId\u003eio.github.myacelw\u003c/groupId\u003e\n    \u003cartifactId\u003emybatis-dynamic-spring\u003c/artifactId\u003e\n    \u003cversion\u003eLatest Version\u003c/version\u003e\n\u003c/dependency\u003e\n\u003c!-- Add your database driver, e.g., H2 --\u003e\n\u003cdependency\u003e\n    \u003cgroupId\u003ecom.h2database\u003c/groupId\u003e\n    \u003cartifactId\u003eh2\u003c/artifactId\u003e\n    \u003cscope\u003eruntime\u003c/scope\u003e\n\u003c/dependency\u003e\n```\n\n#### 3. Configuration\n\nConfigure your database and `mybatis-dynamic` in `application.yml`:\n\n```yaml\nspring:\n  datasource:\n    driver-class-name: org.h2.Driver\n    url: jdbc:h2:./test;MODE=MySQL\n    username: sa\n    password:\n\nmybatis-dynamic:\n  # Automatically update database schema based on models\n  update-model: true\n  # Table name prefix\n  table-prefix: t_\n```\n\n### Your First Model\n\nCreate a simple entity class annotated with `@Model`.\n\n```java\npackage com.example.demo.model;\n\nimport io.github.myacelw.mybatis.dynamic.core.annotation.Model;\nimport io.github.myacelw.mybatis.dynamic.core.annotation.BasicField;\nimport io.github.myacelw.mybatis.dynamic.core.annotation.IdField;\nimport lombok.Data;\nimport lombok.experimental.FieldNameConstants;\n\n@Data\n@FieldNameConstants\n@Model(comment = \"User Table\")\npublic class User {\n\n    @IdField\n    private Integer id;\n\n    @BasicField(ddlComment = \"User Name\", ddlNotNull = true)\n    private String name;\n\n    @BasicField(ddlComment = \"User Age\")\n    private Integer age;\n}\n```\n\n### Enable Scanning\n\nAdd `@EnableModelScan` to your Spring Boot application class.\n\n```java\n@SpringBootApplication\n@EnableModelScan(basePackages = \"com.example.demo.model\")\npublic class Application {\n    public static void main(String[] args) {\n        SpringApplication.run(Application.class, args);\n    }\n}\n```\n\n### Basic CRUD Usage\n\nInject the auto-generated `BaseService` or `BaseDao` to perform operations.\n\n```java\n@RestController\n@RequestMapping(\"/users\")\npublic class UserController {\n\n    // Auto-injected service for the User model\n    @Autowired\n    private BaseService\u003cInteger, User\u003e userService;\n\n    @PostMapping\n    public Integer create(@RequestBody User user) {\n        return userService.insert(user);\n    }\n\n    @GetMapping\n    public List\u003cUser\u003e list() {\n        // Fluent query API\n        return userService.query()\n                .where(c -\u003e c.gt(User.Fields.age, 18))\n                .exec();\n    }\n}\n```\n\n### Zero-Code REST API\n\nThe framework provides a generic `DynamicModelController` that automatically exposes REST endpoints for all registered models.\n\n**Endpoints:**\n- `GET /api/dynamic/{modelName}`: List with pagination/filtering (`?name=John\u0026page=1\u0026size=10`).\n- `GET /api/dynamic/{modelName}/{id}`: Get by ID.\n- `POST /api/dynamic/{modelName}`: Create.\n- `PUT /api/dynamic/{modelName}`: Update.\n- `DELETE /api/dynamic/{modelName}/{id}`: Delete.\n\n**Configuration:**\nEnabled by default. To disable:\n```yaml\nmybatis-dynamic:\n  rest:\n    enabled: false\n```\n\n## Advanced Data Management\n\n### Advanced Entity Modeling\n\n#### Annotations Reference\n\n- **`@Model`**: Marks a class as a managed model.\n  - `tableName`: Custom table name (default: derived from class name).\n  - `comment`: Database table comment.\n  - `logicDelete`: Enable logical deletion.\n  - `disableTableCreateAndAlter`: Disable auto-DDL.\n\n- **`@IdField`**: Marks the primary key field.\n  - `keyGeneratorMode`: ID generation strategy.\n  - `order`: **Required for Composite Primary Keys**.\n  - `ddlColumnType`: Manually specify column type (e.g., \"VARCHAR(64)\").\n\n- **`@BasicField`**: Maps a field to a standard database column.\n  - `columnName`: Custom column name.\n  - `ddlNotNull`: Column cannot be null.\n  - `ddlDefaultValue`: Default value definition.\n  - `ddlCharacterMaximumLength`: Max length for string columns.\n  - `ddlNumericPrecision` / `ddlNumericScale`: Precision for numeric types.\n  - `ddlIndex`: Create an index.\n  - `ddlIndexType`: Type of index (`NORMAL`, `UNIQUE`).\n  - `ddlComment`: Column comment.\n\n- **`@ToOne`**: Defines a \"Many-to-One\" or \"One-to-One\" relationship.\n  - `targetModel`: Target model name (optional if field type is a Model).\n  - `joinField`: Foreign key field in *this* model (default: `{fieldName}Id`).\n\n- **`@ToMany`**: Defines a \"One-to-Many\" or \"Many-to-Many\" relationship.\n  - `targetModel`: Target model name (optional if List generic type is a Model).\n  - `joinField`: Foreign key field in the *target* model (default: `{thisModelName}Id`).\n\n- **`@IgnoreField`**: Excludes the field from database mapping.\n\n#### Relationships \u0026 Querying\n\n**A. One-to-One / Many-to-One**\n\n*Example: A User belongs to a Department.*\n\n```java\n@Data\n@Model\npublic class User {\n    @IdField\n    private String id;\n    private String name;\n    \n    // Defines relation to Department. \n    // Expects \"departmentId\" column in User table.\n    @ToOne \n    private Department department;\n}\n```\n\n**Querying (Auto-Join):**\nSelecting a field from a related entity automatically triggers a **Left Join**.\n\n```java\n// Automatically joins 'department' table to fetch department name\nList\u003cUser\u003e users = userService.query()\n        .select(User.Fields.name, \"department.name\")\n        .exec();\n```\n\n**Explicit Join Configuration:**\nYou can customize the join type (e.g., INNER JOIN) and add ON conditions using the `on()` method.\n\n```java\n// Customize join type and add conditions\nList\u003cUser\u003e users = userService.query()\n        .joins(Join.inner(\"mainDepartment\")\n                   .on(c -\u003e c.eq(\"active\", true)))\n        .exec();\n```\n\n**B. One-to-Many**\n\n*Example: A Department has many Users.*\n\n```java\n@Data\n@Model\npublic class Department {\n    @IdField\n    private String id;\n    private String name;\n    \n    // Defines relation to Users.\n    // Expects \"departmentId\" column in User table.\n    @ToMany \n    private List\u003cUser\u003e users;\n}\n```\n\n**Querying:**\n```java\n// Fetch Department and all its Users\nList\u003cDepartment\u003e depts = departmentService.query()\n        .joins(Join.of(\"users\"))\n        .exec();\n```\n\n**C. Many-to-Many**\n\nImplemented using an **Intermediate Entity** with a composite primary key.\n\n*Example: Students and Courses.*\n\n```java\n// 1. Student\n@Model\npublic class Student {\n    @IdField private String id;\n    \n    // Relation to the intermediate table\n    @ToMany \n    private List\u003cStudentCourse\u003e studentCourses;\n}\n\n// 2. Course\n@Model\npublic class Course {\n    @IdField private String id;\n}\n\n// 3. StudentCourse (Intermediate)\n@Model\npublic class StudentCourse {\n    @IdField(order = 0) private String studentId;\n    @IdField(order = 1) private String courseId;\n\n    @ToOne private Course course;\n}\n```\n\n**Querying:**\n```java\n// Fetch Student and their Courses (joining through StudentCourse)\nList\u003cStudent\u003e students = studentService.query()\n        .joins(Join.of(\"studentCourses.course\")) \n        .exec();\n```\n\n#### Composite Primary Keys\n\nAnnotate multiple fields with `@IdField` and specify their `order`.\n\n```java\n@Model\npublic class UserRole {\n    @IdField(order = 0)\n    private String userId;\n\n    @IdField(order = 1)\n    private String roleId;\n}\n```\n\n#### Inheritance (Single Table)\n\nMap an inheritance hierarchy to a single database table.\n\n```java\n@Model(tableName = \"person\")\n@SubTypes(subTypes = {@SubTypes.SubType(User.class), @SubTypes.SubType(Guest.class)}, subTypeFieldName = \"type\")\npublic abstract class Person {\n    @IdField\n    private String id;\n    private String name;\n}\n\n@Data\npublic class User extends Person {\n    private Integer age;\n}\n\n@Data\npublic class Guest extends Person {\n    private String token;\n}\n```\n\n#### Extensibility (`ExtBean`)\n\nHandle dynamic fields that are not explicitly defined in the Java class.\n\n```java\n@Data\n@Model\npublic class User implements ExtBean {\n    @IdField\n    private String id;\n    private String name;\n\n    @IgnoreField\n    private Map\u003cString, Object\u003e ext = new HashMap\u003c\u003e();\n\n    @Override\n    public Map\u003cString, Object\u003e getExt() {\n        return ext;\n    }\n}\n```\n\n**Usage:**\n```java\n// 1. Add dynamic field definition at runtime\nModel userModel = modelService.getModelForClass(User.class);\nuserModel.getFields().add(Field.string(\"phone\", 100));\nmodelService.update(userModel);\n\n// 2. Use it (Insert/Update/Query)\nUser user = new User();\nuser.getExt().put(\"phone\", \"123456\");\nuserService.insert(user);\n\nList\u003cUser\u003e users = userService.query()\n        .where(c -\u003e c.eq(\"phone\", \"123456\"))\n        .exec();\n```\n\n### Fluent Query API\n\nConstruct complex queries with automatic logical precedence (`AND` \u003e `OR`).\n\n#### 1. Condition Operators\n\nThe `ConditionBuilder` supports a wide range of operators:\n\n- **Simple**: `eq` (equal), `ne` (not equal), `gt` (greater than), `gte`, `lt`, `lte`.\n- **String**: `like`, `startsWith`, `endsWith`, `contains`.\n- **Null Check**: `isNull`, `isNotNull`, `isBlank`, `isNotBlank`.\n- **Collection**: `in`, `notIn`.\n- **Logical**: `and`, `or`, `not` (nested).\n- **Exists**: `exists` (Subquery).\n\n**Optional Variants:**\nAll the above operators (except Null Check and Exists) have an `Optional` variant (e.g., `eqOptional`, `likeOptional`, `inOptional`).\nThese methods automatically ignore the condition if the provided value is `null`, an empty string, or an empty collection.\n\n```java\n// If name is null, \"name = ?\" is not added to SQL.\n// If age is null, \"age \u003e ?\" is not added to SQL.\nuserService.query()\n    .where(c -\u003e c.eqOptional(\"name\", name)\n                 .gtOptional(\"age\", age))\n    .exec();\n```\n\n#### 2. Examples\n\n**Complex Logic**\n```java\n// WHERE (age \u003e 18 AND status = 'Active') OR role = 'Admin'\nuserService.query()\n        .where(c -\u003e c.bracket(b -\u003e b.gt(\"age\", 18).eq(\"status\", \"Active\"))\n                     .or(b -\u003e b.eq(\"role\", \"Admin\")))\n        .joins(Join.of(\"mainDepartment\")) \n        .exec();\n```\n\n**Exists Subquery**\n```java\n// Find users who have at least one order with amount \u003e 100\nuserService.query()\n    .where(c -\u003e c.exists(\"orders\", sub -\u003e sub.gt(\"amount\", 100)))\n    .exec();\n```\n\n### DataManager with Maps\n\nThe `DataManager` interface supports `Map\u003cString, Object\u003e` for scenarios without entity classes.\n\n```java\n// Get DataManager\nDataManager\u003cInteger\u003e dataManager = modelService.getDataManager(\"User\");\n\n// Insert Map\nMap\u003cString, Object\u003e data = new HashMap\u003c\u003e();\ndata.put(\"name\", \"Bob\");\nInteger id = dataManager.insert(data);\n\n// Query returning Maps\nList\u003cMap\u003cString, Object\u003e\u003e results = dataManager.query()\n        .where(c -\u003e c.gt(\"age\", 20))\n        .exec();\n```\n\n### Batch Operations\n\nEfficiently handle large datasets.\n\n```java\nList\u003cUser\u003e userList = ...;\n\n// Batch Insert\nuserService.getDataManager().batchInsert(userList);\n\n// Batch Update (by ID)\nuserService.getDataManager().batchUpdate(userList);\n\n// Batch Update by Condition\nuserService.batchUpdateByConditionChain()\n        .add(c -\u003e c.eq(\"status\", \"Active\"), user1)\n        .add(c -\u003e c.eq(\"status\", \"Inactive\"), user2)\n        .exec();\n```\n\n### Aggregation Queries\n\nPerform SQL aggregate functions (COUNT, SUM, AVG, MAX, MIN) with grouping.\n\n#### 1. Basic Usage\n\nUse `dataManager.aggQuery()` to start an aggregation query chain.\n\n```java\n// Count all users\nMap\u003cString, Object\u003e result = userService.getDataManager()\n    .aggQuery()\n    .count() // Default: COUNT(*), alias \"count\"\n    .exec()\n    .get(0);\nLong count = (Long) result.get(\"count\");\n```\n\n#### 2. Aggregation Functions \u0026 Grouping\n\nYou can specify the field, alias, and grouping.\n\n```java\n// Calculate average age and max age per department\n// SQL: SELECT department_id as deptId, AVG(age) as avgAge, MAX(age) as maxAge FROM user GROUP BY department_id\nList\u003cMap\u003cString, Object\u003e\u003e results = userService.getDataManager()\n    .aggQuery()\n    .groupBy(\"departmentId\", \"deptId\")\n    .avg(\"age\", \"avgAge\")\n    .max(\"age\", \"maxAge\")\n    .exec();\n```\n\n#### 3. Filtering\n\nUse `.where()` to filter data *before* aggregation.\n\n```java\n// Count users older than 18\nList\u003cMap\u003cString, Object\u003e\u003e results = userService.getDataManager()\n    .aggQuery()\n    .count()\n    .where(c -\u003e c.gt(\"age\", 18))\n    .exec();\n```\n\n#### 4. Result Mapping\n\nMap results to a DTO class.\n\n```java\n@Data\npublic class DeptStats {\n    private String deptId;\n    private Double avgAge;\n}\n\nList\u003cDeptStats\u003e stats = userService.getDataManager()\n    .aggQuery(DeptStats.class)\n    .groupBy(\"departmentId\", \"deptId\")\n    .avg(\"age\", \"avgAge\")\n    .exec();\n```\n\n### Recursive Queries\n\nRetrieve hierarchical data (e.g., Department Tree).\n\n```java\nMap\u003cString, Object\u003e tree = departmentService.getRecursiveTreeById(\"dept-id\");\n```\n\n## Expert Features\n\n### Interceptors\n\nHook into data operations (`beforeInsert`, `afterUpdate`, etc.).\n\n```java\n@Component\npublic class MyInterceptor implements DataChangeInterceptor {\n    @Override\n    public void beforeInsert(DataManager\u003cObject\u003e dataManager, Object data) {\n        // ...\n    }\n}\n```\n\n### Auto-Fillers\n\nAutomatically populate fields (e.g., `createTime`, `updateUser`). Implement `Filler` or extend `AbstractCreatorFiller`.\n\n### Permission Management\n\nThe framework provides a robust permission system to control access to data (Row Permissions) and fields (Column Permissions).\n\n#### 1. Concepts\n\n- **Row Permissions (Data Rights)**: Filters data based on conditions (e.g., `tenant_id = 'T001'`). Applied automatically to Select, Update, and Delete operations.\n- **Column Permissions (Field Rights)**: Restricts which fields are visible (in Select) or modifiable (in Insert/Update).\n\n#### 2. Implementing Permissions\n\nImplement the `CurrentUserHolder` interface to provide user context and permissions.\n\n```java\n@Component\npublic class MyUserHolder implements CurrentUserHolder {\n\n    @Override\n    public String getCurrentUserId() {\n        // Return current user ID from Security Context (e.g., Spring Security)\n        return SecurityContextHolder.getContext().getAuthentication().getName();\n    }\n\n    @Override\n    public Permission getCurrentUserPermission(Model model) {\n        // Return permissions based on the model and current user\n        if (\"User\".equals(model.getName())) {\n            // Row Permission: Only see users in the same tenant\n            Condition dataRights = SimpleCondition.eq(\"tenant_id\", getCurrentTenantId());\n            \n            // Column Permission: Cannot see \"password\" or \"salary\"\n            // If list is null, all fields are accessible.\n            List\u003cString\u003e fieldRights = Arrays.asList(\"id\", \"name\", \"age\", \"tenant_id\");\n            \n            return new Permission(fieldRights, dataRights);\n        }\n        return null; // No restrictions\n    }\n}\n```\n\n#### 3. Multi-Tenancy\n\nMulti-tenancy is a primary use case for Row Permissions. By returning a `dataRights` condition (e.g., `tenant_id = current_tenant_id`) in `getCurrentUserPermission`, you ensure strict data isolation across the application.\n\n### Custom Type Handlers\n\n**1. Runtime Data Mapping (MyBatis TypeHandler)**\n\nUse standard MyBatis `TypeHandler` to convert data between Java and Database at runtime.\n\n```java\n@BasicField(typeHandler = MyJsonTypeHandler.class)\nprivate MyObject data;\n```\n\n**2. DDL Type Mapping (ColumnTypeHandler)**\n\nControl how a Java type maps to a Database Column Definition (e.g., `VARCHAR(255)`) during auto-DDL.\n\n```java\n@Component\npublic class MyCustomTypeHandler implements ColumnTypeHandler {\n    @Override\n    public boolean doSetColumnType(Column column, Class\u003c?\u003e javaType, DataBaseDialect dialect, Field field) {\n        if (javaType == MyCustomType.class) {\n            column.setDataType(\"VARCHAR\");\n            column.setCharacterMaximumLength(500);\n            return true; // Handled\n        }\n        return false;\n    }\n}\n```\n\n## Community\n\n- **Issues**: Please file an issue for bugs or feature requests.\n- **Discussions**: Join the discussions on GitHub.\n\n## License\n\nThis project is licensed under the [Apache License 2.0](LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmyacelw%2Fmybatis-dynamic","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmyacelw%2Fmybatis-dynamic","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmyacelw%2Fmybatis-dynamic/lists"}