!182 feat:Active Record 功能

Merge pull request !182 from 王帅/main
This commit is contained in:
Michael Yang 2023-07-25 06:43:03 +00:00 committed by Gitee
commit 1da9aed0cd
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
12 changed files with 1125 additions and 19 deletions

View File

@ -63,6 +63,7 @@ export default defineConfig({
{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'},

View File

@ -0,0 +1,141 @@
# 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
功能十分简单,只需继承 [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 接口,可以使用 [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));
```

View File

@ -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());
}
}

View File

@ -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());
}
}

View File

@ -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;

View File

@ -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());
}
}

View File

@ -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;
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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;
}

View File

@ -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);
}
}