Encode the usage rules of MyBatis-Plus in DDD4J projects. The LLM will use standard MyBatis-Plus syntax, but it does not conform to project conventions.
Why this skill is needed
The LLM will use implements Serializable to define entities—DDD4J requires extends BaseEntity<T extends Model<?>>(ActiveRecord mode). The LLM will write #{entity.beginTime}in XML—DDD4J requires #{model.beginTime}(@Param("model")). The LLM does not know these conventions.
Capability Boundaries
✅ Strong Suits
- Entity inheritance chain — BaseEntity→Model(ActiveRecord),PaginationEntity→BaseEntity
- Audit fields — createBy/createTime (INSERT fill), updateBy/updateTime (INSERT_UPDATE fill)
- Logical deletion — @TableLogic marks the isDeleted field
- @Param("model") convention — the parameter name of getPagedList is model, not entity
- Pagination encapsulation — PaginationEntity (default 15 per page, Oracle-style offset=(pageNo-1)*limit+1)
- Type handlers — BooleanEnum (0/1), JSON (two sets), List/Set/Array
- BaseMapper built-in methods — getPagedList/setStatus/getCountBy*
❌ Out of Scope
- Entity/Controller/Service inheritance hierarchy → ddd4j-core
- Jackson JSON configuration → ddd4j-jackson
The most common mistakes made by LLMs
| # | Error | Correct approach |
|---|---|---|
| 1 | implements Serializable |
extends BaseEntity<T>(extend Model, ActiveRecord) |
| 2 | Redeclaring createBy/createTime | BaseEntity already declares them; subclasses should not add them again |
| 3 | XML writes #{entity.beginTime} |
write #{model.beginTime} |
| 4 | new Page<T>(1, 10) |
use PaginationEntity<T> encapsulation |
| 5 | Logical deletion writes UPDATE SET is_delete=1 |
Use @TableLogic; MyBatis-Plus handles it automatically |
| 6 | Custom Boolean field mapping | Use BooleanEnum + CustomBooleanEnumTypeHandler |
| 7 | Manual offset calculation (pageNo-1)*limit |
PaginationEntity.getOffset() is already encapsulated |
Core rules quick reference
// ✅ 正确:实体定义
@Data
@TableName("sys_user")
public class SysUser extends BaseEntity<SysUser> { // Model<T> → ActiveRecord
// ↓ 已继承,不再声明
// Long createBy, createTime, updateBy, updateTime
// Integer isDeleted (@TableLogic)
// LocalDateTime beginTime, endTime (@TableField(exist=false), @JsonIgnore)
// String keywords, params (@TableField(exist=false), @JsonIgnore)
private String username;
private String status; // BooleanEnum 映射: 0=否, 1=是
}
// ✅ 分页查询
PaginationEntity<SysUser> entity = new PaginationEntity<>();
entity.setPageNo(1); // 第1页
entity.setLimit(15); // 默认15条
entity.setBeginTime(LocalDateTime.now().minusDays(7));
List<SysUser> list = baseService.getPagedList(
new Page<>(entity.getPageNo(), entity.getLimit()), entity
);
// ✅ Mapper XML(注意参数名 model)
<select id="getPagedList" resultType="SysUser">
SELECT * FROM sys_user
WHERE is_deleted = 0
<if test="model.beginTime != null">
AND create_time >= #{model.beginTime}
</if>
</select>
// ✅ 内置方法(BaseServiceImpl 已提供)
baseService.setStatus(id, "1"); // @Transactional
baseService.getCountByName("admin");
baseService.getCountByCode("ADMIN");
baseService.getCountByParent(parentId);
baseService.getValue("some_key"); // 从缓存读取
Gotchas
- Entities must extend BaseEntity, not implement Serializable — loses ActiveRecord capability
- @Param("model") is a fixed convention — XML references must be #{model.xxx}
- PaginationEntity.getOffset() is Oracle-style —
((pageNo−1)*limit+1), not starting from 0 - beginTime/endTime are on the Entity, not in a separate QueryDTO — add
@TableField(exist=false)and it is fine - BooleanEnum maps to Integer 0/1 — the database does not use the native Boolean type
- There are two sets of JSON type handlers — core uses fastjson2 (jdbc package), cmet uses hutool
- Logical deletion condition is automatically concatenated — SQL does not need to write
is_deleted = 0(but it is recommended to add it for complex queries) - setStatus is @Transactional — subclass overrides must also add the transaction annotation
Data Privacy
This skill does not collect, store, or transmit any user data.