mirror of
https://gitee.com/mybatis-flex/mybatis-flex.git
synced 2025-12-07 09:08:24 +08:00
Merge branch 'main' of https://gitee.com/dcrpp/mybatis-flex
# Conflicts: # mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/config/ColumnConfig.java # mybatis-flex-codegen/src/main/java/com/mybatisflex/codegen/entity/Column.java
This commit is contained in:
commit
10d2080a94
19
changes.md
19
changes.md
@ -1,6 +1,25 @@
|
||||
# MyBatis-Flex ChangeLog
|
||||
|
||||
|
||||
## v1.5.3 20230725:
|
||||
- 新增:添加 UpdateChain 方便用于对数据进行更新
|
||||
- 新增:添加对 ActiveRecord 设计模式的支持,感谢 @Suomm
|
||||
- 新增:代码生成器 ColumnConfig 增加 propertyType. 可以用于自定通用属性的类型。感谢 @jerryzhengsz1
|
||||
- 新增:添加 selectOneWithRelationsById(根据主表主键来查询 1 条数据) 方法,感谢 @barql
|
||||
- 新增:QueryWrapper.groupBy 支持 Lambda 表达式的功能,感谢 @Suomm
|
||||
- 新增:QueryWrapper 添加 `not like` 构建的支持
|
||||
- 优化:重命名 QueryWrapperChain 为 QueryChain,保存和 UpdateChain 统一
|
||||
- 修复:`@Relation` 关联查询注解,在指定 selectColumns 出错的问题,感谢 @zhy_balck
|
||||
- 修复:代码生成器配置 `camelToUnderline` 属性时 entity 生成后编译错误的问题,感谢 @genomics_zcg
|
||||
- 文档:优化 APT 的文档描述有错别字的问题,感谢 @zhangjx1992
|
||||
- 文档:添加关于 ActiveRecord 的相关文档,感谢 @Suomm
|
||||
- 文档:修改代码生成器对 EnjoyTemplate 的描述错误的问题
|
||||
- 文档:添加更多关于链式查询的相关文档
|
||||
- 文档:重构文档链接,链式操作的相关文档
|
||||
- 文档:修改代码生成器对 EnjoyTemplate 的描述错误的问题
|
||||
|
||||
|
||||
|
||||
## v1.5.2 20230723:
|
||||
- 新增:添加 QueryWrapperChain 用于链式调用查询或者操作数据,感谢 @Suomm
|
||||
- 新增:添加 DbChain 链式调用 Db + Row 的相关方法和功能,感谢 @Suomm
|
||||
|
||||
@ -60,9 +60,10 @@ export default defineConfig({
|
||||
{text: '基础查询', link: '/zh/base/query'},
|
||||
{text: '关联查询', link: '/zh/base/relations-query'},
|
||||
{text: '批量操作', link: '/zh/base/batch'},
|
||||
{text: '链式操作', link: '/zh/base/chain'},
|
||||
{text: 'QueryWrapper', link: '/zh/base/querywrapper'},
|
||||
{text: 'QueryWrapperChain', link: '/zh/base/query-wrapper-chain'},
|
||||
{text: 'Db + Row', link: '/zh/base/db-row'},
|
||||
{text: 'Active Record', link: '/zh/base/active-record'},
|
||||
{text: 'IService', link: '/zh/base/service'},
|
||||
{text: 'SpringBoot 配置文件', link: '/zh/base/configuration'},
|
||||
{text: 'MyBatisFlexCustomizer', link: '/zh/base/mybatis-flex-customizer'},
|
||||
|
||||
138
docs/zh/base/active-record.md
Normal file
138
docs/zh/base/active-record.md
Normal file
@ -0,0 +1,138 @@
|
||||
# Active Record
|
||||
|
||||
[Active Record 模式](http://www.martinfowler.com/eaaCatalog/activeRecord.html)出自 Martin Fowler
|
||||
写的《[企业应用架构模式](https://book.douban.com/subject/4826290/)》书中。在 Active Record
|
||||
模式中,对象中既有持久存储的数据,也有针对数据的操作。Active Record 模式把数据存取逻辑作为对象的一部分,处理对象的用户知道如何把数据写入数据库,还知道如何从数据库中读出数据。
|
||||
|
||||
在 MyBatis-Flex 中实现 Active Record
|
||||
功能十分简单,只需让 Entity 类继承 [Model](https://gitee.com/mybatis-flex/mybatis-flex/blob/main/mybatis-flex-core/src/main/java/com/mybatisflex/core/activerecord/Model.java)
|
||||
即可。
|
||||
|
||||
::: tip 注意事项
|
||||
- 使用 Active Record 功能时,项目中必须注入对应实体类的 BaseMapper 对象。
|
||||
- 如果不想手动创建 Mapper 接口,可以使用 [代码生成器](../others/codegen.md) 或 [APT](../others/apt.md#配置文件和选项) 辅助生成。
|
||||
:::
|
||||
|
||||
## 使用示例
|
||||
|
||||
在以下示例当中,使用了 [Lombok](https://www.projectlombok.org/) 对实体类进行了增强,以便我们全链式调用:
|
||||
|
||||
1. `@Table` 标记了实体类对应的数据表。
|
||||
2. `@Data` 为我们生成了 setter/getter、toString、equals、hashCode 等方法,
|
||||
其中 `staticConstructor = "create"` 为我们创建了一个 `create()` 静态方法用于链式调用。
|
||||
3. `@Accessors(chain = true)` 为我们开启了 `return this;` 这样既可以被序列化,又可以链式调用。
|
||||
|
||||
```java
|
||||
|
||||
@Table("tb_account")
|
||||
@Accessors(chain = true)
|
||||
@Data(staticConstructor = "create")
|
||||
public class Account extends Model<Account> {
|
||||
|
||||
@Id(keyType = KeyType.Auto)
|
||||
private Long id;
|
||||
private String userName;
|
||||
private Integer age;
|
||||
private Date birthday;
|
||||
}
|
||||
```
|
||||
|
||||
这样我们就可以流畅的使用 Active Record 功能了:
|
||||
|
||||
```java
|
||||
@RestController
|
||||
@RequestMapping("/account")
|
||||
public class AccountController {
|
||||
|
||||
@PostMapping("save")
|
||||
public boolean save(@RequestBody Account account) {
|
||||
return account.save();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 保存数据
|
||||
|
||||
`Model` 提供了 `save` 方法来保存数据,调用该方法前需要将保存数据填充:
|
||||
|
||||
```java
|
||||
Account.create()
|
||||
.setUserName("张三")
|
||||
.setAge(18)
|
||||
.setBirthday(new Date())
|
||||
.save();
|
||||
```
|
||||
|
||||
## 删除数据
|
||||
|
||||
`Model` 提供了 `remove` 方法来删除数据:
|
||||
|
||||
- 根据主键删除
|
||||
|
||||
```java
|
||||
Account.create()
|
||||
.setId(1L)
|
||||
.removeById();
|
||||
```
|
||||
|
||||
- 根据条件删除
|
||||
|
||||
```java
|
||||
Account.create()
|
||||
.where(Account::getId).eq(1L)
|
||||
.remove();
|
||||
```
|
||||
|
||||
## 更新数据
|
||||
|
||||
`Model` 提供了 `update` 方法来更新数据,调用该方法前需要将更新数据填充:
|
||||
|
||||
- 根据主键更新
|
||||
|
||||
```java
|
||||
Account.create()
|
||||
.setId(1L)
|
||||
.setAge(100)
|
||||
.updateById();
|
||||
```
|
||||
|
||||
- 根据条件更新
|
||||
|
||||
```java
|
||||
Account.create()
|
||||
.setAge(100)
|
||||
.where(Account::getId).eq(1L)
|
||||
.update();
|
||||
```
|
||||
|
||||
## 查询数据
|
||||
|
||||
### 查询一条数据
|
||||
|
||||
`Model` 提供了 `one` 方法来查询一条数据:
|
||||
|
||||
```java
|
||||
Account.create()
|
||||
.where(Account::getId).eq(1L)
|
||||
.one();
|
||||
```
|
||||
|
||||
### 查询多条数据
|
||||
|
||||
`Model` 提供了 `list` 方法来查询多条数据:
|
||||
|
||||
```java
|
||||
Account.create()
|
||||
.where(Account::getAge).ge(18)
|
||||
.list();
|
||||
```
|
||||
|
||||
### 查询分页数据
|
||||
|
||||
`Model` 提供了 `page` 方法来查询分页数据:
|
||||
|
||||
```java
|
||||
Account.create()
|
||||
.where(Account::getAge).ge(18)
|
||||
.page(Page.of(1,10));
|
||||
```
|
||||
@ -170,3 +170,28 @@ update tb_account
|
||||
set user_name = "michael", age = (select ... from ... )
|
||||
where id = 100
|
||||
```
|
||||
|
||||
## UpdateChain
|
||||
|
||||
UpdateChain 是一个对 `UpdateEntity`、`UpdateWrapper` 等进行封装的一个工具类,方便用户用于进行链式操作。
|
||||
|
||||
假设我们要更新 `Account` 的 `userName` 为 "`张三`",更新年龄在之前的基础上加 1,更新代码如下:
|
||||
|
||||
```java
|
||||
@Test
|
||||
public void testUpdateChain() {
|
||||
UpdateChain.of(Account.class)
|
||||
.set(Account::getUserName, "张三")
|
||||
.setRaw(Account::getAge, "age + 1")
|
||||
.where(Account::getId).eq(1)
|
||||
.update();
|
||||
}
|
||||
```
|
||||
以上方法调用时,MyBatis-Flex 内部执行的 SQL 如下:
|
||||
|
||||
```sql
|
||||
UPDATE `tb_account` SET `user_name` = '张三' , `age` = age + 1
|
||||
WHERE `id` = 1
|
||||
```
|
||||
|
||||
更多关于 **链式操作**,请点击这个 [这里](./chain.html#updatechain-示例)。
|
||||
|
||||
@ -1,7 +1,12 @@
|
||||
# QueryWrapperChain
|
||||
# 链式操作
|
||||
|
||||
`QueryWrapperChain.java` 是一个对 `QueryWrapper` 进行链式调用封装的一个类,在 Service 中,
|
||||
我们可以调用 `service.queryChain()` 获得该实例。
|
||||
在 MyBatis-Flex 中,内置了 `QueryChain.java` 和 `UpdateChain.java` 用于对数据进行链式查询操作和链式数据操作(修改和删除)。
|
||||
|
||||
- **QueryChain**:链式查询
|
||||
- **UpdateChain**:链式更新
|
||||
|
||||
|
||||
## QueryChain 示例
|
||||
|
||||
例如,查询文章列表代码如下:
|
||||
|
||||
@ -24,29 +29,76 @@ class ArticleServiceTest {
|
||||
}
|
||||
```
|
||||
|
||||
若不是在 Service 中,我们也可以通过 `QueryWrapperChain.create` 方法,自己创建一个 `QueryWrapperChain` 实例,代码如下:
|
||||
若不是在 Service 中,我们也可以通过 `QueryChain.create` 方法,自己创建一个 `QueryChain` 实例,代码如下:
|
||||
|
||||
```java
|
||||
List<Article> articles = QueryWrapperChain.create(mapper)
|
||||
List<Article> articles = QueryChain.of(mapper)
|
||||
.select(ARTICLE.ALL_COLUMNS)
|
||||
.from(ARTICLE)
|
||||
.where(ARTICLE.ID.ge(100))
|
||||
.list();
|
||||
```
|
||||
|
||||
## QueryWrapperChain 的方法
|
||||
## UpdateChain 示例
|
||||
|
||||
假设我们要更新 `Account` 的 `userName` 为 "`张三`",更新年龄在之前的基础上加 1,更新代码如下:
|
||||
|
||||
```java
|
||||
@Test
|
||||
public void testUpdateChain1() {
|
||||
UpdateChain.of(Account.class)
|
||||
.set(Account::getUserName, "张三")
|
||||
.setRaw(Account::getAge, "age + 1")
|
||||
.where(Account::getId).eq(1)
|
||||
.update();
|
||||
}
|
||||
```
|
||||
以上方法调用时,MyBatis-Flex 内部执行的 SQL 如下:
|
||||
|
||||
```sql
|
||||
UPDATE `tb_account` SET `user_name` = '张三' , `age` = age + 1
|
||||
WHERE `id` = 1
|
||||
```
|
||||
|
||||
**另一个示例:**
|
||||
|
||||
```java
|
||||
@Test
|
||||
public void testUpdateChain2() {
|
||||
|
||||
//更新数据
|
||||
UpdateChain.of(Account.class)
|
||||
.set(Account::getAge, ACCOUNT.AGE.add(1))
|
||||
.where(Account::getId).ge(100)
|
||||
.and(Account::getAge).eq(18)
|
||||
.update();
|
||||
|
||||
//查询所有数据并打印
|
||||
QueryChain.of(accountMapper)
|
||||
.list()
|
||||
.forEach(System.out::println);
|
||||
}
|
||||
```
|
||||
通过 `UpdateChain` 进行 `update()`,其执行的 SQL 如下:
|
||||
|
||||
```sql
|
||||
UPDATE `tb_account` SET `age` = `age` + 1
|
||||
WHERE `id` >= 100 AND `age` = 18
|
||||
```
|
||||
|
||||
|
||||
|
||||
## QueryChain 的方法
|
||||
|
||||
- one():获取一条数据
|
||||
- list():获取多条数据
|
||||
- page():分页查询
|
||||
- obj():当 SQL 查询只返回 1 列数据的时候,且只有 1 条数据时,可以使用此方法
|
||||
- objList():当 SQL 查询只返回 1 列数据的时候,可以使用此方法
|
||||
- remove():删除数据
|
||||
- update(entity):更新数据
|
||||
- count():查询数据条数
|
||||
- exists():是否存在,判断 count 是否大于 0
|
||||
|
||||
## 扩展方法
|
||||
## QueryChain 扩展方法
|
||||
|
||||
### `one()` 系列方法
|
||||
|
||||
@ -1,6 +1,25 @@
|
||||
# MyBatis-Flex ChangeLog
|
||||
|
||||
|
||||
## v1.5.3 20230725:
|
||||
- 新增:添加 UpdateChain 方便用于对数据进行更新
|
||||
- 新增:添加对 ActiveRecord 设计模式的支持,感谢 @Suomm
|
||||
- 新增:代码生成器 ColumnConfig 增加 propertyType. 可以用于自定通用属性的类型。感谢 @jerryzhengsz1
|
||||
- 新增:添加 selectOneWithRelationsById(根据主表主键来查询 1 条数据) 方法,感谢 @barql
|
||||
- 新增:QueryWrapper.groupBy 支持 Lambda 表达式的功能,感谢 @Suomm
|
||||
- 新增:QueryWrapper 添加 `not like` 构建的支持
|
||||
- 优化:重命名 QueryWrapperChain 为 QueryChain,保存和 UpdateChain 统一
|
||||
- 修复:`@Relation` 关联查询注解,在指定 selectColumns 出错的问题,感谢 @zhy_balck
|
||||
- 修复:代码生成器配置 `camelToUnderline` 属性时 entity 生成后编译错误的问题,感谢 @genomics_zcg
|
||||
- 文档:优化 APT 的文档描述有错别字的问题,感谢 @zhangjx1992
|
||||
- 文档:添加关于 ActiveRecord 的相关文档,感谢 @Suomm
|
||||
- 文档:修改代码生成器对 EnjoyTemplate 的描述错误的问题
|
||||
- 文档:添加更多关于链式查询的相关文档
|
||||
- 文档:重构文档链接,链式操作的相关文档
|
||||
- 文档:修改代码生成器对 EnjoyTemplate 的描述错误的问题
|
||||
|
||||
|
||||
|
||||
## v1.5.2 20230723:
|
||||
- 新增:添加 QueryWrapperChain 用于链式调用查询或者操作数据,感谢 @Suomm
|
||||
- 新增:添加 DbChain 链式调用 Db + Row 的相关方法和功能,感谢 @Suomm
|
||||
|
||||
@ -39,7 +39,7 @@ VALUES (1, '张三', 18, '2020-01-11'),
|
||||
<dependency>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>mybatis-flex-spring-boot-starter</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mysql</groupId>
|
||||
|
||||
@ -12,12 +12,12 @@
|
||||
<dependency>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>mybatis-flex-core</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>mybatis-flex-processor</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
```
|
||||
@ -28,12 +28,12 @@
|
||||
<dependency>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>mybatis-flex-spring</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>mybatis-flex-processor</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
``````
|
||||
@ -44,12 +44,12 @@
|
||||
<dependency>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>mybatis-flex-spring-boot-starter</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>mybatis-flex-processor</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
```
|
||||
@ -70,7 +70,7 @@
|
||||
<path>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>mybatis-flex-processor</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</path>
|
||||
</annotationProcessorPaths>
|
||||
</configuration>
|
||||
|
||||
@ -88,7 +88,7 @@ public class AccountTableDef extends TableDef {
|
||||
#upperCase, lowerCase, upperCamelCase, lowerCamelCase
|
||||
processor.tableDef.propertiesNameStyle = upperCase
|
||||
```
|
||||
风格支持 4 中配置,默认(未配置时)为 upperCase,支持的配置分别为:
|
||||
风格支持 4 种配置,默认(未配置时)为 upperCase,支持的配置分别为:
|
||||
|
||||
- upperCase:大写 + 下划线,例如:USER_NAME
|
||||
- lowerCase:小写 + 下划线,例如:user_name
|
||||
@ -173,7 +173,7 @@ processor.allInTables.package=com.example.entity.table
|
||||
|
||||
## 和 Lombok、Mapstruct 整合
|
||||
|
||||
在很多项目中,用到了 Lombok 帮我们减少代码编写,同时用到 Mapstruct 进行 bean 转换。使用到 Lombok 和 Mapstruct 时,其要求我们再
|
||||
在很多项目中,用到了 Lombok 帮我们减少代码编写,同时用到 Mapstruct 进行 bean 转换。使用到 Lombok 和 Mapstruct 时,其要求我们在
|
||||
pom.xml 添加 `annotationProcessorPaths` 配置,
|
||||
此时,我们也需要把 MyBatis-Flex 的 annotation 添加到 `annotationProcessorPaths` 配置里去,如下图所示:
|
||||
|
||||
@ -219,7 +219,7 @@ pom.xml 添加 `annotationProcessorPaths` 配置,
|
||||
```
|
||||
dependencies {
|
||||
...
|
||||
annotationProcessor 'com.mybatis-flex:mybatis-flex-processor:<version>1.5.2</version>'
|
||||
annotationProcessor 'com.mybatis-flex:mybatis-flex-processor:<version>1.5.3</version>'
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
<dependency>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>mybatis-flex-codegen</artifactId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</dependency>
|
||||
```
|
||||
|
||||
@ -474,40 +474,30 @@ public class EnjoyTemplate implements ITemplate {
|
||||
private Engine engine;
|
||||
|
||||
public EnjoyTemplate() {
|
||||
engine = Engine.create("mybatis-flex", engine -> {
|
||||
engine.setToClassPathSourceFactory();
|
||||
engine.addSharedMethod(StringUtil.class);
|
||||
Engine engine = Engine.use(engineName);
|
||||
if (engine == null) {
|
||||
engine = Engine.create(engineName, e -> {
|
||||
e.addSharedStaticMethod(StringUtil.class);
|
||||
e.setSourceFactory(new FileAndClassPathSourceFactory());
|
||||
});
|
||||
}
|
||||
this.engine = engine;
|
||||
|
||||
// 以下配置将支持 user.girl 表达式去调用 user 对象的 boolean isGirl() 方法
|
||||
Engine.addFieldGetterToFirst(new FieldGetters.IsMethodFieldGetter());
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 entity 的方法实现
|
||||
*/
|
||||
@Override
|
||||
public void generateEntity(GlobalConfig globalConfig, Table table, File entityJavaFile) throws Exception {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("globalConfig", globalConfig);
|
||||
params.put("table", table);
|
||||
|
||||
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(entityJavaFile);
|
||||
engine.getTemplate("/templates/enjoy/entity.tpl").render(params, fileOutputStream);
|
||||
public void generate(Map<String, Object> params, String templateFilePath, File generateFile) {
|
||||
if (!generateFile.getParentFile().exists() && !generateFile.getParentFile().mkdirs()) {
|
||||
throw new IllegalStateException("Can not mkdirs by dir: " + generateFile.getParentFile());
|
||||
}
|
||||
// 开始生成文件
|
||||
try (FileOutputStream fileOutputStream = new FileOutputStream(generateFile)) {
|
||||
engine.getTemplate(templateFilePath).render(params, fileOutputStream);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成 mapper 的方法实现
|
||||
*/
|
||||
@Override
|
||||
public void generateMapper(GlobalConfig globalConfig, Table table, File mapperJavaFile) throws Exception {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put("globalConfig", globalConfig);
|
||||
params.put("table", table);
|
||||
|
||||
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(mapperJavaFile);
|
||||
engine.getTemplate("/templates/enjoy/mapper.tpl").render(params, fileOutputStream);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -216,6 +216,9 @@ public class ColumnConfig implements Serializable {
|
||||
public void setTenantId(Boolean tenantId) {
|
||||
this.tenantId = tenantId;
|
||||
}
|
||||
public Class<?> getPropertyType() {
|
||||
return propertyType;
|
||||
}
|
||||
|
||||
public String getPropertyType() {
|
||||
return propertyType;
|
||||
|
||||
@ -76,6 +76,31 @@ public class StrategyConfig {
|
||||
*/
|
||||
private Set<String> unGenerateTables;
|
||||
|
||||
/**
|
||||
* 需要忽略的列 全局配置。
|
||||
*/
|
||||
private Set<String> ignoreColumns;
|
||||
|
||||
/**
|
||||
* 获取需要忽略的列 全局配置。
|
||||
*/
|
||||
public Set<String> getIgnoreColumns() {
|
||||
return ignoreColumns;
|
||||
}
|
||||
/**
|
||||
* 设置需要忽略的列 全局配置。
|
||||
*/
|
||||
public StrategyConfig setIgnoreColumns(String... columns) {
|
||||
if (ignoreColumns == null) {
|
||||
ignoreColumns = new HashSet<>();
|
||||
}
|
||||
for (String column : columns) {
|
||||
if (column != null && column.trim().length() > 0) {
|
||||
ignoreColumns.add(column.trim().toLowerCase());
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置要生成的模式
|
||||
|
||||
@ -131,6 +131,12 @@ public class Table {
|
||||
|
||||
public void addColumn(Column column) {
|
||||
|
||||
//排除忽略列
|
||||
if (globalConfig.getStrategyConfig().getIgnoreColumns() != null &&
|
||||
globalConfig.getStrategyConfig().getIgnoreColumns().contains(column.getName().toLowerCase())) {
|
||||
return;
|
||||
}
|
||||
|
||||
//主键
|
||||
if (primaryKeys != null && primaryKeys.contains(column.getName())) {
|
||||
column.setPrimaryKey(true);
|
||||
@ -239,7 +245,7 @@ public class Table {
|
||||
tableAnnotation.append(", schema = \"").append(tableConfig.getSchema()).append("\"");
|
||||
}
|
||||
if (tableConfig.getCamelToUnderline() != null) {
|
||||
tableAnnotation.append(", camelToUnderline = \"").append(tableConfig.getCamelToUnderline()).append("\"");
|
||||
tableAnnotation.append(", camelToUnderline = ").append(tableConfig.getCamelToUnderline());
|
||||
}
|
||||
if (tableConfig.getInsertListenerClass() != null) {
|
||||
tableAnnotation.append(", onInsert = ").append(tableConfig.getInsertListenerClass().getSimpleName()).append(".class");
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -490,6 +490,16 @@ public interface BaseMapper<T> {
|
||||
return MapperUtil.queryRelations(this, MapperUtil.getSelectOneResult(selectListByQuery(queryWrapper)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据主表主键来查询 1 条数据。
|
||||
*
|
||||
* @param id 主表主键
|
||||
* @return 实体类数据
|
||||
*/
|
||||
default T selectOneWithRelationsById(Serializable id) {
|
||||
return MapperUtil.queryRelations(this, selectOneById(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据查询条件来查询 1 条数据。
|
||||
*
|
||||
|
||||
@ -24,7 +24,7 @@ public class FlexConsts {
|
||||
}
|
||||
|
||||
public static final String NAME = "MyBatis-Flex";
|
||||
public static final String VERSION = "1.5.2";
|
||||
public static final String VERSION = "1.5.3";
|
||||
|
||||
public static final String DEFAULT_PRIMARY_FIELD = "id";
|
||||
|
||||
|
||||
@ -0,0 +1,150 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mybatisflex.core.activerecord;
|
||||
|
||||
import com.mybatisflex.core.BaseMapper;
|
||||
import com.mybatisflex.core.mybatis.Mappers;
|
||||
import com.mybatisflex.core.table.TableInfo;
|
||||
import com.mybatisflex.core.table.TableInfoFactory;
|
||||
import com.mybatisflex.core.util.SqlUtil;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* <p>使用 {@link BaseMapper} 进行 CRUD 操作的实体类的抽象接口。
|
||||
*
|
||||
* <p>使用接口是为了方便拓展,该接口提供了简单的根据 <b>主键</b> 操作数据的方法,
|
||||
* 实现类可以进行其他方法的扩展。
|
||||
*
|
||||
* @param <T> 实体类类型
|
||||
* @author 王帅
|
||||
* @since 2023-07-23
|
||||
*/
|
||||
@SuppressWarnings({"unused", "unchecked"})
|
||||
public interface MapperModel<T> {
|
||||
|
||||
/**
|
||||
* 获取实体类对应的 {@link BaseMapper} 接口。
|
||||
*
|
||||
* @return {@link BaseMapper} 接口
|
||||
*/
|
||||
default BaseMapper<T> baseMapper() {
|
||||
return Mappers.ofEntityClass((Class<T>) getClass());
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>获取实体类主键数据。
|
||||
*
|
||||
* <p>可以拓展该方法提高效率,例如:
|
||||
* <pre>{@code
|
||||
* return new Object[]{id};
|
||||
* }</pre>
|
||||
*
|
||||
* @return 主键数据数组
|
||||
*/
|
||||
default Object[] getPkValues() {
|
||||
TableInfo tableInfo = TableInfoFactory.ofEntityClass(getClass());
|
||||
return tableInfo.buildPkSqlArgs(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据(自动忽略 {@code null} 值)。
|
||||
*
|
||||
* @return {@code true} 保存成功,{@code false} 保存失败
|
||||
*/
|
||||
default boolean save() {
|
||||
return save(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存数据,并设置是否忽略 {@code null} 值。
|
||||
*
|
||||
* @param ignoreNulls 是否忽略 {@code null} 值
|
||||
* @return {@code true} 保存成功,{@code false} 保存失败
|
||||
*/
|
||||
default boolean save(boolean ignoreNulls) {
|
||||
return SqlUtil.toBool(baseMapper().insert((T) this, ignoreNulls));
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存或者更新数据,如果实体类主键没有值,则 <b>保存</b> 数据;如果实体类主键有值,则
|
||||
* <b>更新</b> 数据(全部自动忽略 {@code null} 值)。
|
||||
*
|
||||
* @return {@code true} 保存或更新成功,{@code false} 保存或更新失败
|
||||
*/
|
||||
default boolean saveOrUpdate() {
|
||||
return saveOrUpdate(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存或者更新数据,如果实体类主键没有值,则 <b>保存</b> 数据;如果实体类主键有值,则
|
||||
* <b>更新</b> 数据,并设置是否忽略 {@code null} 值。
|
||||
*
|
||||
* @param ignoreNulls 是否忽略 {@code null} 值
|
||||
* @return {@code true} 保存或更新成功,{@code false} 保存或更新失败
|
||||
*/
|
||||
default boolean saveOrUpdate(boolean ignoreNulls) {
|
||||
return SqlUtil.toBool(baseMapper().insertOrUpdate((T) this, ignoreNulls));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据实体类主键删除数据。
|
||||
*
|
||||
* @return {@code true} 删除成功,{@code false} 删除失败
|
||||
*/
|
||||
default boolean removeById() {
|
||||
return SqlUtil.toBool(baseMapper().deleteById(getPkValues()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据实体类主键更新数据(自动忽略 {@code null} 值)。
|
||||
*
|
||||
* @return {@code true} 更新成功,{@code false} 更新失败
|
||||
*/
|
||||
default boolean updateById() {
|
||||
return updateById(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据实体类主键更新数据,并设置是否忽略 {@code null} 值。
|
||||
*
|
||||
* @param ignoreNulls 是否忽略 {@code null} 值
|
||||
* @return {@code true} 更新成功,{@code false} 更新失败
|
||||
*/
|
||||
default boolean updateById(boolean ignoreNulls) {
|
||||
return SqlUtil.toBool(baseMapper().update((T) this, ignoreNulls));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据实体类主键获取一条数据。
|
||||
*
|
||||
* @return 数据
|
||||
*/
|
||||
default T oneById() {
|
||||
return baseMapper().selectOneById(getPkValues());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据实体类主键获取一条数据,并封装为 {@link Optional} 返回。
|
||||
*
|
||||
* @return 数据
|
||||
*/
|
||||
default Optional<T> oneByIdOpt() {
|
||||
return Optional.ofNullable(oneById());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mybatisflex.core.activerecord;
|
||||
|
||||
import com.mybatisflex.core.activerecord.query.QueryModel;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.util.SqlUtil;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Active Record 模型。
|
||||
*
|
||||
* @param <T> 实体类类型
|
||||
* @author 王帅
|
||||
* @since 2023-07-24
|
||||
*/
|
||||
@SuppressWarnings({"unused", "unchecked"})
|
||||
public abstract class Model<T extends Model<T>>
|
||||
extends QueryModel<T>
|
||||
implements MapperModel<T> {
|
||||
|
||||
/**
|
||||
* 根据实体类构建的条件删除数据。
|
||||
*
|
||||
* @return {@code true} 删除成功,{@code false} 删除失败
|
||||
*/
|
||||
public boolean remove() {
|
||||
return SqlUtil.toBool(baseMapper().deleteByQuery(getQueryWrapper()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据实体类构建的条件更新数据(自动忽略 {@code null} 值)。
|
||||
*
|
||||
* @return {@code true} 更新成功,{@code false} 更新失败
|
||||
*/
|
||||
public boolean update() {
|
||||
return update(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据实体类构建的条件更新数据,并设置是否忽略 {@code null} 值。
|
||||
*
|
||||
* @param ignoreNulls 是否忽略 {@code null} 值
|
||||
* @return {@code true} 更新成功,{@code false} 更新失败
|
||||
*/
|
||||
public boolean update(boolean ignoreNulls) {
|
||||
return SqlUtil.toBool(baseMapper().updateByQuery((T) this, ignoreNulls, getQueryWrapper()));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据实体类构建的条件查询数据数量。
|
||||
*
|
||||
* @return 数据数量
|
||||
*/
|
||||
public long count() {
|
||||
return baseMapper().selectCountByQuery(getQueryWrapper());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据实体类构建的条件判断数据是否存在。
|
||||
*
|
||||
* @return {@code true} 数据存在,{@code false} 数据不存在
|
||||
*/
|
||||
public boolean exists() {
|
||||
return SqlUtil.toBool(count());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据实体类构建的条件获取一条数据。
|
||||
*
|
||||
* @return 数据
|
||||
*/
|
||||
public T one() {
|
||||
return baseMapper().selectOneByQuery(getQueryWrapper().limit(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据实体类构建的条件获取一条数据,并封装为 {@link Optional} 返回。
|
||||
*
|
||||
* @return 数据
|
||||
*/
|
||||
public Optional<T> oneOpt() {
|
||||
return Optional.ofNullable(one());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据实体类构建的条件获取多条数据。
|
||||
*
|
||||
* @return 数据列表
|
||||
*/
|
||||
public List<T> list() {
|
||||
return baseMapper().selectListByQuery(getQueryWrapper());
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据实体类构建的条件获取分页数据。
|
||||
*
|
||||
* @param page 分页对象
|
||||
* @return 分页数据
|
||||
*/
|
||||
public Page<T> page(Page<T> page) {
|
||||
return baseMapper().paginate(page, getQueryWrapper());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Active Record 功能。
|
||||
*/
|
||||
package com.mybatisflex.core.activerecord;
|
||||
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.mybatisflex.core.activerecord.query;
|
||||
|
||||
|
||||
import com.mybatisflex.core.query.QueryColumn;
|
||||
import com.mybatisflex.core.util.LambdaGetter;
|
||||
import com.mybatisflex.core.util.LambdaUtil;
|
||||
|
||||
/**
|
||||
* Lambda 排序构建器。
|
||||
*
|
||||
* @author 王帅
|
||||
* @since 2023-07-25
|
||||
*/
|
||||
public class OrderByBuilder<R extends QueryModel<R>> {
|
||||
|
||||
private final R queryModel;
|
||||
private final QueryColumn queryColumn;
|
||||
|
||||
public <T> OrderByBuilder(R queryModel, LambdaGetter<T> getter) {
|
||||
this.queryModel = queryModel;
|
||||
this.queryColumn = LambdaUtil.getQueryColumn(getter);
|
||||
}
|
||||
|
||||
public R asc() {
|
||||
return queryModel.orderBy(queryColumn.asc());
|
||||
}
|
||||
|
||||
public R desc() {
|
||||
return queryModel.orderBy(queryColumn.desc());
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,178 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mybatisflex.core.activerecord.query;
|
||||
|
||||
import com.mybatisflex.annotation.Column;
|
||||
import com.mybatisflex.core.query.*;
|
||||
import com.mybatisflex.core.util.LambdaGetter;
|
||||
import com.mybatisflex.core.util.LambdaUtil;
|
||||
|
||||
/**
|
||||
* <p>实体类条件查询构建模型。
|
||||
*
|
||||
* <p>该类内部维护了一个 {@link QueryWrapper} 属性,用来构建查询条件。
|
||||
* 通过实体类属性构建的查询条件都是值等于,该扩展用于非等于值构建,及一些其他方法。
|
||||
* 如果不想通过实体类直接构建查询条件,可以不继承该类。
|
||||
*
|
||||
* @param <T> 实体类类型
|
||||
* @author 王帅
|
||||
* @since 2023-07-24
|
||||
*/
|
||||
@SuppressWarnings({"unused", "unchecked"})
|
||||
public abstract class QueryModel<T extends QueryModel<T>> {
|
||||
|
||||
@Column(ignore = true)
|
||||
private QueryWrapper queryWrapper;
|
||||
|
||||
protected QueryWrapper getQueryWrapper() {
|
||||
if (queryWrapper == null) {
|
||||
queryWrapper = QueryWrapper.create();
|
||||
}
|
||||
return queryWrapper;
|
||||
}
|
||||
|
||||
public T select() {
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T select(String... columns) {
|
||||
getQueryWrapper().select(columns);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T select(QueryColumn... queryColumns) {
|
||||
getQueryWrapper().select(queryColumns);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public <E> T select(LambdaGetter<E>... columns) {
|
||||
getQueryWrapper().select(columns);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T select(QueryColumn[]... queryColumns) {
|
||||
getQueryWrapper().select(queryColumns);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T where(QueryCondition queryCondition) {
|
||||
getQueryWrapper().where(queryCondition);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T where(String sql) {
|
||||
getQueryWrapper().where(sql);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T where(String sql, Object... params) {
|
||||
getQueryWrapper().where(sql, params);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public <E> WhereBuilder<T> where(LambdaGetter<E> column) {
|
||||
return new WhereBuilder<>((T) this, LambdaUtil.getQueryColumn(column), SqlConnector.AND);
|
||||
}
|
||||
|
||||
public T and(QueryCondition queryCondition) {
|
||||
getQueryWrapper().and(queryCondition);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T and(String sql) {
|
||||
getQueryWrapper().and(sql);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T and(String sql, Object... params) {
|
||||
getQueryWrapper().and(sql, params);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public <E> WhereBuilder<T> and(LambdaGetter<E> column) {
|
||||
return new WhereBuilder<>((T) this, LambdaUtil.getQueryColumn(column), SqlConnector.AND);
|
||||
}
|
||||
|
||||
public T or(QueryCondition queryCondition) {
|
||||
getQueryWrapper().or(queryCondition);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T or(String sql) {
|
||||
getQueryWrapper().or(sql);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T or(String sql, Object... params) {
|
||||
getQueryWrapper().or(sql, params);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public <E> WhereBuilder<T> or(LambdaGetter<E> column) {
|
||||
return new WhereBuilder<>((T) this, LambdaUtil.getQueryColumn(column), SqlConnector.OR);
|
||||
}
|
||||
|
||||
public T groupBy(String... names) {
|
||||
getQueryWrapper().groupBy(names);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T groupBy(QueryColumn... columns) {
|
||||
getQueryWrapper().groupBy(columns);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public <E> T groupBy(LambdaGetter<E>... columns) {
|
||||
getQueryWrapper().groupBy(columns);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T having(QueryCondition queryCondition) {
|
||||
getQueryWrapper().having(queryCondition);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T orderBy(QueryOrderBy... orderBys) {
|
||||
getQueryWrapper().orderBy(orderBys);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T orderBy(String... orderBys) {
|
||||
getQueryWrapper().orderBy(orderBys);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public <E> OrderByBuilder<T> orderBy(LambdaGetter<E> column) {
|
||||
return new OrderByBuilder<>((T) this, column);
|
||||
}
|
||||
|
||||
public T limit(Integer rows) {
|
||||
getQueryWrapper().limit(rows);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T offset(Integer offset) {
|
||||
getQueryWrapper().offset(offset);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
public T limit(Integer offset, Integer rows) {
|
||||
getQueryWrapper().limit(offset, rows);
|
||||
return (T) this;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,352 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.mybatisflex.core.activerecord.query;
|
||||
|
||||
import com.mybatisflex.core.query.CPI;
|
||||
import com.mybatisflex.core.query.QueryColumn;
|
||||
import com.mybatisflex.core.query.SqlConnector;
|
||||
import com.mybatisflex.core.util.LambdaGetter;
|
||||
import com.mybatisflex.core.util.LambdaUtil;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
/**
|
||||
* Lambda 条件构建器。
|
||||
*
|
||||
* @author 王帅
|
||||
* @since 2023-07-24
|
||||
*/
|
||||
public class WhereBuilder<R extends QueryModel<R>> {
|
||||
|
||||
private final R queryModel;
|
||||
private final QueryColumn queryColumn;
|
||||
private final SqlConnector connector;
|
||||
|
||||
public WhereBuilder(R queryModel, QueryColumn queryColumn, SqlConnector connector) {
|
||||
this.queryModel = queryModel;
|
||||
this.queryColumn = queryColumn;
|
||||
this.connector = connector;
|
||||
}
|
||||
|
||||
public R eq(Object value) {
|
||||
if (value != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.eq(value), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R eq(Object value, Predicate<T> when) {
|
||||
if (value != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.eq(value, when), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R eq(LambdaGetter<T> value) {
|
||||
return eq(LambdaUtil.getQueryColumn(value));
|
||||
}
|
||||
|
||||
public <T> R eq(LambdaGetter<T> value, Predicate<T> when) {
|
||||
return eq(LambdaUtil.getQueryColumn(value), when);
|
||||
}
|
||||
|
||||
public R ne(Object value) {
|
||||
if (value != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.ne(value), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R ne(Object value, Predicate<T> when) {
|
||||
if (value != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.ne(value, when), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R ne(LambdaGetter<T> value) {
|
||||
return ne(LambdaUtil.getQueryColumn(value));
|
||||
}
|
||||
|
||||
public <T> R ne(LambdaGetter<T> value, Predicate<T> when) {
|
||||
return ne(LambdaUtil.getQueryColumn(value), when);
|
||||
}
|
||||
|
||||
public R like(Object value) {
|
||||
if (value != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.like(value), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R like(Object value, Predicate<T> when) {
|
||||
if (value != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.like(value, when), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public R likeLeft(Object value) {
|
||||
if (value != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.likeLeft(value), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R likeLeft(Object value, Predicate<T> when) {
|
||||
if (value != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.likeLeft(value, when), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public R likeRight(Object value) {
|
||||
if (value != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.likeRight(value), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R likeRight(Object value, Predicate<T> when) {
|
||||
if (value != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.likeRight(value, when), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public R gt(Object value) {
|
||||
if (value != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.gt(value), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R gt(Object value, Predicate<T> when) {
|
||||
if (value != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.gt(value, when), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R gt(LambdaGetter<T> value) {
|
||||
return gt(LambdaUtil.getQueryColumn(value));
|
||||
}
|
||||
|
||||
public <T> R gt(LambdaGetter<T> value, Predicate<T> when) {
|
||||
return gt(LambdaUtil.getQueryColumn(value), when);
|
||||
}
|
||||
|
||||
public R ge(Object value) {
|
||||
if (value != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.ge(value), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R ge(Object value, Predicate<T> when) {
|
||||
if (value != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.ge(value, when), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R ge(LambdaGetter<T> value) {
|
||||
return ge(LambdaUtil.getQueryColumn(value));
|
||||
}
|
||||
|
||||
public <T> R ge(LambdaGetter<T> value, Predicate<T> when) {
|
||||
return ge(LambdaUtil.getQueryColumn(value), when);
|
||||
}
|
||||
|
||||
public R lt(Object value) {
|
||||
if (value != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.lt(value), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R lt(Object value, Predicate<T> when) {
|
||||
if (value != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.lt(value, when), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R lt(LambdaGetter<T> value) {
|
||||
return lt(LambdaUtil.getQueryColumn(value));
|
||||
}
|
||||
|
||||
public <T> R lt(LambdaGetter<T> value, Predicate<T> when) {
|
||||
return lt(LambdaUtil.getQueryColumn(value), when);
|
||||
}
|
||||
|
||||
public R le(Object value) {
|
||||
if (value != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.le(value), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R le(Object value, Predicate<T> when) {
|
||||
if (value != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.le(value, when), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R le(LambdaGetter<T> value) {
|
||||
return le(LambdaUtil.getQueryColumn(value));
|
||||
}
|
||||
|
||||
public <T> R le(LambdaGetter<T> value, Predicate<T> when) {
|
||||
return le(LambdaUtil.getQueryColumn(value), when);
|
||||
}
|
||||
|
||||
public R isNull() {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.isNull(), connector);
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R isNull(Predicate<T> when) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.isNull(when), connector);
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public R isNotNull() {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.isNotNull(), connector);
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R isNotNull(Predicate<T> when) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.isNotNull(when), connector);
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public R in(Object... arrays) {
|
||||
if (arrays != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.in(arrays), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R in(Object[] arrays, Predicate<T> when) {
|
||||
//忽略 QueryWrapper.in("name", null) 的情况
|
||||
if (arrays != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.in(arrays, when), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public R in(R queryModel) {
|
||||
if (queryModel != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.in(queryModel), connector);
|
||||
}
|
||||
return this.queryModel;
|
||||
}
|
||||
|
||||
public <T> R in(R queryModel, Predicate<T> when) {
|
||||
if (queryModel != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.in(queryModel, when), connector);
|
||||
}
|
||||
return this.queryModel;
|
||||
}
|
||||
|
||||
public R in(Collection<?> collection) {
|
||||
if (queryModel != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.in(collection), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R in(Collection<?> collection, Predicate<T> when) {
|
||||
if (queryModel != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.in(collection, when), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public R notIn(Object... arrays) {
|
||||
if (queryModel != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.notIn(arrays), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R notIn(Object[] arrays, Predicate<T> when) {
|
||||
if (queryModel != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.notIn(arrays, when), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public R notIn(Collection<?> collection) {
|
||||
if (queryModel != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.notIn(collection), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R notIn(Collection<?> collection, Predicate<T> when) {
|
||||
if (queryModel != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.notIn(collection, when), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public R notIn(R queryModel) {
|
||||
if (queryModel != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.notIn(queryModel), connector);
|
||||
}
|
||||
return this.queryModel;
|
||||
}
|
||||
|
||||
public <T> R notIn(R queryModel, Predicate<T> when) {
|
||||
if (queryModel != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.notIn(queryModel, when), connector);
|
||||
}
|
||||
return this.queryModel;
|
||||
}
|
||||
|
||||
public R between(Object start, Object end) {
|
||||
if (queryModel != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.between(start, end), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R between(Object start, Object end, Predicate<T> when) {
|
||||
if (queryModel != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.between(start, end, when), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public R notBetween(Object start, Object end) {
|
||||
if (queryModel != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.notBetween(start, end), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
public <T> R notBetween(Object start, Object end, Predicate<T> when) {
|
||||
if (queryModel != null) {
|
||||
CPI.addWhereQueryCondition(queryModel.getQueryWrapper(), queryColumn.notBetween(start, end, when), connector);
|
||||
}
|
||||
return queryModel;
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 条件查询功能。
|
||||
*/
|
||||
package com.mybatisflex.core.activerecord.query;
|
||||
@ -23,10 +23,14 @@ import org.apache.ibatis.session.SqlSession;
|
||||
import org.apache.ibatis.session.SqlSessionFactory;
|
||||
import org.apache.ibatis.util.MapUtil;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.InvocationHandler;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
@ -77,6 +81,8 @@ public class Mappers {
|
||||
|
||||
|
||||
static class MapperHandler implements InvocationHandler {
|
||||
private static final Set<String> ignoreMethods = new HashSet<>(Arrays.asList("queryChain","updateChain"));
|
||||
private static final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
private Class<?> mapperClass;
|
||||
private final SqlSessionFactory sqlSessionFactory = FlexGlobalConfig.getDefaultConfig().getSqlSessionFactory();
|
||||
private final ExecutorType executorType = FlexGlobalConfig.getDefaultConfig().getConfiguration().getDefaultExecutorType();
|
||||
|
||||
@ -125,6 +125,10 @@ public class CPI {
|
||||
return queryWrapper.getWhereQueryCondition();
|
||||
}
|
||||
|
||||
public static void addWhereQueryCondition(QueryWrapper queryWrapper, QueryCondition queryCondition, SqlConnector connector) {
|
||||
queryWrapper.addWhereQueryCondition(queryCondition, connector);
|
||||
}
|
||||
|
||||
public static List<QueryColumn> getGroupByColumns(QueryWrapper queryWrapper) {
|
||||
return queryWrapper.getGroupByColumns();
|
||||
}
|
||||
|
||||
@ -29,28 +29,16 @@ import java.util.Optional;
|
||||
* @author 王帅
|
||||
* @since 2023-07-22
|
||||
*/
|
||||
public class QueryWrapperChain<T> extends QueryWrapperAdapter<QueryWrapperChain<T>> {
|
||||
public class QueryChain<T> extends QueryWrapperAdapter<QueryChain<T>> {
|
||||
|
||||
private final BaseMapper<T> baseMapper;
|
||||
|
||||
public QueryWrapperChain(BaseMapper<T> baseMapper) {
|
||||
public QueryChain(BaseMapper<T> baseMapper) {
|
||||
this.baseMapper = baseMapper;
|
||||
}
|
||||
|
||||
public static <E> QueryWrapperChain<E> create(BaseMapper<E> baseMapper) {
|
||||
return new QueryWrapperChain<>(baseMapper);
|
||||
}
|
||||
|
||||
public boolean remove() {
|
||||
return SqlUtil.toBool(baseMapper.deleteByQuery(this));
|
||||
}
|
||||
|
||||
public boolean update(T entity) {
|
||||
return SqlUtil.toBool(baseMapper.updateByQuery(entity, this));
|
||||
}
|
||||
|
||||
public boolean update(T entity, boolean ignoreNulls) {
|
||||
return SqlUtil.toBool(baseMapper.updateByQuery(entity, ignoreNulls, this));
|
||||
public static <E> QueryChain<E> of(BaseMapper<E> baseMapper) {
|
||||
return new QueryChain<>(baseMapper);
|
||||
}
|
||||
|
||||
public long count() {
|
||||
@ -579,6 +579,18 @@ public class QueryWrapper extends BaseQueryWrapper<QueryWrapper> {
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> QueryWrapper groupBy(LambdaGetter<T> column) {
|
||||
addGroupByColumns(LambdaUtil.getQueryColumn(column));
|
||||
return this;
|
||||
}
|
||||
|
||||
public <T> QueryWrapper groupBy(LambdaGetter<T>... columns) {
|
||||
for (LambdaGetter<T> column : columns) {
|
||||
groupBy(LambdaUtil.getQueryColumn(column));
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public QueryWrapper having(QueryCondition queryCondition) {
|
||||
addHavingQueryCondition(queryCondition, SqlConnector.AND);
|
||||
return this;
|
||||
|
||||
@ -536,6 +536,18 @@ public class QueryWrapperAdapter<R extends QueryWrapperAdapter<R>> extends Query
|
||||
return (R) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> R groupBy(LambdaGetter<T> column) {
|
||||
super.groupBy(column);
|
||||
return (R) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> R groupBy(LambdaGetter<T>... columns) {
|
||||
super.groupBy(columns);
|
||||
return (R) this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public R having(QueryCondition queryCondition) {
|
||||
super.having(queryCondition);
|
||||
|
||||
@ -20,7 +20,7 @@ import com.mybatisflex.core.exception.FlexExceptions;
|
||||
import com.mybatisflex.core.paginate.Page;
|
||||
import com.mybatisflex.core.query.QueryCondition;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.mybatisflex.core.query.QueryWrapperChain;
|
||||
import com.mybatisflex.core.query.QueryChain;
|
||||
import com.mybatisflex.core.row.Db;
|
||||
import com.mybatisflex.core.util.ClassUtil;
|
||||
import com.mybatisflex.core.util.CollectionUtil;
|
||||
@ -529,8 +529,8 @@ public interface IService<T> {
|
||||
return QueryWrapper.create();
|
||||
}
|
||||
|
||||
default QueryWrapperChain<T> queryChain() {
|
||||
return new QueryWrapperChain<>(getMapper());
|
||||
default QueryChain<T> queryChain() {
|
||||
return new QueryChain<>(getMapper());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (c) 2022-2023, Mybatis-Flex (fuhai999@gmail.com).
|
||||
* <p>
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.mybatisflex.core.update;
|
||||
|
||||
import com.mybatisflex.core.BaseMapper;
|
||||
import com.mybatisflex.core.exception.FlexExceptions;
|
||||
import com.mybatisflex.core.mybatis.Mappers;
|
||||
import com.mybatisflex.core.query.QueryColumn;
|
||||
import com.mybatisflex.core.query.QueryWrapperAdapter;
|
||||
import com.mybatisflex.core.util.ClassUtil;
|
||||
import com.mybatisflex.core.util.LambdaGetter;
|
||||
import com.mybatisflex.core.util.SqlUtil;
|
||||
import com.mybatisflex.core.util.UpdateEntity;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
/**
|
||||
* 用于数据更新、删除的链式操作
|
||||
*
|
||||
* @author michale
|
||||
* @since 2023-07-25
|
||||
*/
|
||||
public class UpdateChain<T> extends QueryWrapperAdapter<UpdateChain<T>> {
|
||||
|
||||
private final BaseMapper<T> baseMapper;
|
||||
private final T entity;
|
||||
private final UpdateWrapper entityWrapper;
|
||||
|
||||
public static <T> UpdateChain<T> of(Class<T> entityClass) {
|
||||
BaseMapper<T> baseMapper = Mappers.ofEntityClass(entityClass);
|
||||
return new UpdateChain<>(baseMapper);
|
||||
}
|
||||
|
||||
public UpdateChain(BaseMapper<T> baseMapper) {
|
||||
this.baseMapper = baseMapper;
|
||||
this.entity = createEntity(ClassUtil.getUsefulClass(baseMapper.getClass()));
|
||||
this.entityWrapper = (UpdateWrapper) entity;
|
||||
}
|
||||
|
||||
private T createEntity(Class<?> mapperClass) {
|
||||
Type type = mapperClass.getGenericInterfaces()[0];
|
||||
if (type instanceof ParameterizedType) {
|
||||
Class<T> modelClass = (Class<T>) ((ParameterizedType) type).getActualTypeArguments()[0];
|
||||
return UpdateEntity.of(modelClass);
|
||||
}
|
||||
throw FlexExceptions.wrap("Can not get entity class from mapper: " + mapperClass.getName());
|
||||
}
|
||||
|
||||
public static <E> UpdateChain<E> create(BaseMapper<E> baseMapper) {
|
||||
return new UpdateChain<>(baseMapper);
|
||||
}
|
||||
|
||||
|
||||
public UpdateChain<T> set(String property, Object value) {
|
||||
entityWrapper.set(property, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public UpdateChain<T> set(LambdaGetter<T> getter, Object value) {
|
||||
entityWrapper.set(getter, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public UpdateChain<T> set(QueryColumn queryColumn, Object value) {
|
||||
entityWrapper.set(queryColumn, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateChain<T> setRaw(String property, Object value) {
|
||||
entityWrapper.setRaw(property, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public UpdateChain<T> setRaw(LambdaGetter<T> getter, Object value) {
|
||||
entityWrapper.setRaw(getter, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
public UpdateChain<T> setRaw(QueryColumn queryColumn, Object value) {
|
||||
entityWrapper.set(queryColumn, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public boolean remove() {
|
||||
return SqlUtil.toBool(baseMapper.deleteByQuery(this));
|
||||
}
|
||||
|
||||
public boolean update() {
|
||||
return SqlUtil.toBool(baseMapper.updateByQuery(entity, this));
|
||||
}
|
||||
|
||||
}
|
||||
@ -26,6 +26,9 @@ import org.apache.ibatis.javassist.util.proxy.ProxyObject;
|
||||
import java.io.Serializable;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author michael
|
||||
*/
|
||||
public interface UpdateWrapper extends Serializable {
|
||||
|
||||
default Map<String, Object> getUpdates() {
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>mybatis-flex-test</artifactId>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -0,0 +1,72 @@
|
||||
package com.mybatisflex.test;
|
||||
|
||||
import com.mybatisflex.core.MybatisFlexBootstrap;
|
||||
import com.mybatisflex.core.audit.AuditManager;
|
||||
import com.mybatisflex.core.audit.ConsoleMessageCollector;
|
||||
import com.mybatisflex.core.audit.MessageCollector;
|
||||
import com.mybatisflex.core.query.QueryChain;
|
||||
import com.mybatisflex.core.update.UpdateChain;
|
||||
import org.apache.ibatis.logging.stdout.StdOutImpl;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import static com.mybatisflex.test.table.AccountTableDef.ACCOUNT;
|
||||
|
||||
public class UpdateChainTest {
|
||||
|
||||
static AccountMapper accountMapper;
|
||||
|
||||
@BeforeClass
|
||||
public static void init() {
|
||||
DataSource dataSource = new EmbeddedDatabaseBuilder()
|
||||
.setType(EmbeddedDatabaseType.H2)
|
||||
.addScript("schema.sql")
|
||||
.addScript("data.sql")
|
||||
.build();
|
||||
|
||||
MybatisFlexBootstrap bootstrap = MybatisFlexBootstrap.getInstance()
|
||||
.setDataSource(dataSource)
|
||||
.setLogImpl(StdOutImpl.class)
|
||||
.addMapper(AccountMapper.class)
|
||||
.start();
|
||||
|
||||
//开启审计功能
|
||||
AuditManager.setAuditEnable(true);
|
||||
|
||||
//设置 SQL 审计收集器
|
||||
MessageCollector collector = new ConsoleMessageCollector();
|
||||
AuditManager.setMessageCollector(collector);
|
||||
|
||||
accountMapper = bootstrap.getMapper(AccountMapper.class);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChain() {
|
||||
UpdateChain.of(Account.class)
|
||||
.set(Account::getUserName,"张三")
|
||||
.setRaw(Account::getAge,"age + 1")
|
||||
.where(Account::getId).eq(1)
|
||||
.update();
|
||||
|
||||
Account account = accountMapper.selectOneById(1);
|
||||
System.out.println(account);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateChain1() {
|
||||
UpdateChain.of(Account.class)
|
||||
.set(Account::getAge, ACCOUNT.AGE.add(1))
|
||||
.where(Account::getId).ge(100)
|
||||
.and(Account::getAge).eq(18)
|
||||
.update();
|
||||
|
||||
QueryChain.of(accountMapper)
|
||||
.list()
|
||||
.forEach(System.out::println);
|
||||
}
|
||||
}
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>mybatis-flex-test</artifactId>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -17,7 +17,9 @@
|
||||
package com.mybatisflex.test.model;
|
||||
|
||||
import com.mybatisflex.annotation.Id;
|
||||
import com.mybatisflex.annotation.KeyType;
|
||||
import com.mybatisflex.annotation.Table;
|
||||
import com.mybatisflex.core.activerecord.Model;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@ -28,35 +30,42 @@ import java.util.Objects;
|
||||
* @since 2023-06-07
|
||||
*/
|
||||
@Table("tb_good")
|
||||
public class Good {
|
||||
public class Good extends Model<Good> {
|
||||
|
||||
@Id
|
||||
@Id(keyType = KeyType.Auto)
|
||||
private Integer goodId;
|
||||
private String name;
|
||||
private double price;
|
||||
private Double price;
|
||||
|
||||
public static Good create() {
|
||||
return new Good();
|
||||
}
|
||||
|
||||
public Integer getGoodId() {
|
||||
return goodId;
|
||||
}
|
||||
|
||||
public void setGoodId(Integer goodId) {
|
||||
public Good setGoodId(Integer goodId) {
|
||||
this.goodId = goodId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
public Good setName(String name) {
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getPrice() {
|
||||
public Double getPrice() {
|
||||
return price;
|
||||
}
|
||||
|
||||
public void setPrice(double price) {
|
||||
public Good setPrice(Double price) {
|
||||
this.price = price;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -79,23 +88,20 @@ public class Good {
|
||||
|
||||
Good good = (Good) o;
|
||||
|
||||
if (Double.compare(good.price, price) != 0) {
|
||||
return false;
|
||||
}
|
||||
if (!Objects.equals(goodId, good.goodId)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(name, good.name);
|
||||
if (!Objects.equals(name, good.name)) {
|
||||
return false;
|
||||
}
|
||||
return Objects.equals(price, good.price);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result;
|
||||
long temp;
|
||||
result = goodId != null ? goodId.hashCode() : 0;
|
||||
int result = goodId != null ? goodId.hashCode() : 0;
|
||||
result = 31 * result + (name != null ? name.hashCode() : 0);
|
||||
temp = Double.doubleToLongBits(price);
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
result = 31 * result + (price != null ? price.hashCode() : 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -19,9 +19,12 @@ package com.mybatisflex.test.mapper;
|
||||
import com.mybatisflex.core.mybatis.Mappers;
|
||||
import com.mybatisflex.core.query.QueryWrapper;
|
||||
import com.mybatisflex.test.model.Good;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
|
||||
import static com.mybatisflex.test.model.table.GoodTableDef.GOOD;
|
||||
|
||||
/**
|
||||
* @author 王帅
|
||||
* @since 2023-07-23
|
||||
@ -31,12 +34,75 @@ class ActiveRecordTest {
|
||||
|
||||
@Test
|
||||
void testMapper() {
|
||||
Good good = new Good();
|
||||
good.setPrice(28);
|
||||
Good good = Good.create();
|
||||
|
||||
GoodMapper goodMapper = Mappers.ofMapperClass(GoodMapper.class);
|
||||
good.setPrice(28.0);
|
||||
|
||||
GoodMapper goodMapper = (GoodMapper) Mappers.ofEntityClass(Good.class);
|
||||
|
||||
goodMapper.selectListByQuery(QueryWrapper.create(good));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testInsert() {
|
||||
boolean saved = Good.create()
|
||||
.setPrice(28.0)
|
||||
.setName("摆渡人")
|
||||
.save();
|
||||
|
||||
Assertions.assertTrue(saved);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testUpdate() {
|
||||
Good.create()
|
||||
.setGoodId(11)
|
||||
.setPrice(38.0)
|
||||
.updateById();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testDelete() {
|
||||
boolean removed = Good.create()
|
||||
.setGoodId(1)
|
||||
.removeById();
|
||||
|
||||
Assertions.assertTrue(removed);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSelectById() {
|
||||
Good good = Good.create()
|
||||
.setGoodId(11)
|
||||
.oneById();
|
||||
|
||||
System.out.println(good);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSelectOne() {
|
||||
Good good1 = Good.create()
|
||||
.setName("摆渡人")
|
||||
.one();
|
||||
|
||||
Good good2 = Good.create()
|
||||
.where(GOOD.NAME.eq("摆渡人"))
|
||||
.one();
|
||||
|
||||
Good good3 = Good.create()
|
||||
.where(Good::getName).eq("摆渡人")
|
||||
.one();
|
||||
|
||||
Assertions.assertEquals(good1, good2);
|
||||
Assertions.assertEquals(good1, good3);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSelectList() {
|
||||
Good.create()
|
||||
.where(GOOD.PRICE.ge(28.0))
|
||||
.list()
|
||||
.forEach(System.out::println);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
<parent>
|
||||
<artifactId>mybatis-flex-test</artifactId>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>mybatis-flex-test</artifactId>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
<parent>
|
||||
<artifactId>parent</artifactId>
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
|
||||
4
pom.xml
4
pom.xml
@ -7,7 +7,7 @@
|
||||
<groupId>com.mybatis-flex</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
<version>1.5.2</version>
|
||||
<version>1.5.3</version>
|
||||
|
||||
<name>mybatis-flex</name>
|
||||
<url>https://mybatis-flex.com</url>
|
||||
@ -54,7 +54,7 @@
|
||||
<maven.compiler.source>8</maven.compiler.source>
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
|
||||
<mybatis-flex.version>1.5.2</mybatis-flex.version>
|
||||
<mybatis-flex.version>1.5.3</mybatis-flex.version>
|
||||
|
||||
<mybatis.version>3.5.13</mybatis.version>
|
||||
<mybatis-spring.version>2.1.0</mybatis-spring.version>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user