!144 属性查询支持嵌套属性

Merge pull request !144 from 王帅/main
This commit is contained in:
Michael Yang 2023-07-16 02:32:49 +00:00 committed by Gitee
commit 75a1df800e
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
11 changed files with 530 additions and 108 deletions

View File

@ -15,29 +15,119 @@
*/
package com.mybatisflex.core.field;
import com.mybatisflex.core.query.QueryWrapper;
import java.io.Serializable;
/**
* 查询属性的信息
*/
@SuppressWarnings("rawtypes")
public class FieldQuery implements Serializable {
private String field;
private QueryWrapper queryWrapper;
private String className;
private String fieldName;
private FieldType fieldType = FieldType.AUTO;
private boolean prevent;
private QueryBuilder queryBuilder;
public String getField() {
return field;
public String getClassName() {
return className;
}
public void setField(String field) {
this.field = field;
public void setClassName(String className) {
this.className = className;
}
public QueryWrapper getQueryWrapper() {
return queryWrapper;
public String getFieldName() {
return fieldName;
}
public void setQueryWrapper(QueryWrapper queryWrapper) {
this.queryWrapper = queryWrapper;
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public FieldType getFieldType() {
return fieldType;
}
public void setFieldType(FieldType fieldType) {
this.fieldType = fieldType;
}
public boolean isPrevent() {
return prevent;
}
public void setPrevent(boolean prevent) {
this.prevent = prevent;
}
public QueryBuilder getQueryBuilder() {
return queryBuilder;
}
public void setQueryBuilder(QueryBuilder queryBuilder) {
this.queryBuilder = queryBuilder;
}
public static class Builder<T> {
private final FieldQuery fieldQuery;
public Builder(String className, String fieldName) {
this.fieldQuery = new FieldQuery();
this.fieldQuery.setClassName(className);
this.fieldQuery.setFieldName(fieldName);
}
/**
* 设置属性类型可选默认自动识别
*
* @param fieldType 属性类型
* @return 构建者
*/
public Builder<T> fieldType(FieldType fieldType) {
this.fieldQuery.setFieldType(fieldType);
return this;
}
/**
* 阻止对嵌套类属性的查询只对 {@link FieldType#COLLECTION}
* {@link FieldType#ENTITY} 两种属性类型有效
*
* @return 构建者
*/
public Builder<T> prevent() {
this.fieldQuery.setPrevent(true);
return this;
}
/**
* 设置是否阻止对嵌套类属性的查询只对 {@link FieldType#COLLECTION}
* {@link FieldType#ENTITY} 两种属性类型有效
*
* @param prevent 是否阻止对嵌套类属性查询
* @return 构建者
*/
public Builder<T> prevent(boolean prevent) {
this.fieldQuery.setPrevent(prevent);
return this;
}
/**
* 设置查询这个属性的 {@code QueryWrapper} 对象
*
* @param queryBuilder 查询包装器
* @return 构建者
*/
public Builder<T> queryWrapper(QueryBuilder<T> queryBuilder) {
this.fieldQuery.setQueryBuilder(queryBuilder);
return this;
}
protected FieldQuery build() {
return this.fieldQuery;
}
}
}

View File

@ -15,36 +15,60 @@
*/
package com.mybatisflex.core.field;
import com.mybatisflex.core.exception.FlexAssert;
import com.mybatisflex.core.util.LambdaGetter;
import com.mybatisflex.core.util.LambdaUtil;
import java.io.Serializable;
/**
* 属性查询构建者
*
* @param <T> 属性所在实体类类型
* @author 开源海哥
* @author 王帅
*/
public class FieldQueryBuilder<T> implements Serializable {
private T entity;
private FieldQuery fieldQuery = new FieldQuery();
private FieldQuery.Builder<?> builder;
public FieldQueryBuilder(T entity) {
this.entity = entity;
/**
* 为指定属性创建查询
*
* @param fn Lambda 引用
* @return {@link FieldQuery.Builder} 构建者
*/
public FieldQuery.Builder<T> field(LambdaGetter<T> fn) {
return createBuilder(fn);
}
public FieldQueryBuilder<T> field(String field) {
fieldQuery.setField(field);
return this;
/**
* 为指定嵌套属性创建查询
*
* @param <N> 嵌套属性类型
* @param fn Lambda 引用
* @return {@link FieldQuery.Builder} 构建者
*/
public <N> FieldQuery.Builder<N> nestedField(LambdaGetter<N> fn) {
return createBuilder(fn);
}
public FieldQueryBuilder<T> field(LambdaGetter<T> fn) {
return field(LambdaUtil.getFieldName(fn));
}
public FieldQueryBuilder<T> queryWrapper(QueryBuilder<T> fun) {
fieldQuery.setQueryWrapper(fun.build(entity));
return this;
/**
* <p>创建 {@link FieldQuery.Builder} 用于构建属性类型与 {@code QueryWrapper} 用于查询
*
* <p>该方法主要用作于创建构建者对象以及泛型的转换
*/
@SuppressWarnings({"rawtypes", "unchecked"})
private <R> FieldQuery.Builder<R> createBuilder(LambdaGetter fn) {
FlexAssert.notNull(fn, "Field can not be null.");
String className = LambdaUtil.getClassName(fn);
String fieldName = LambdaUtil.getFieldName(fn);
builder = new FieldQuery.Builder<>(className, fieldName);
return (FieldQuery.Builder<R>) builder;
}
public FieldQuery build() {
return fieldQuery;
return builder.build();
}
}

View File

@ -0,0 +1,171 @@
/*
* 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.field;
import com.mybatisflex.core.BaseMapper;
import com.mybatisflex.core.exception.FlexExceptions;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.row.Row;
import com.mybatisflex.core.util.ClassUtil;
import com.mybatisflex.core.util.CollectionUtil;
import com.mybatisflex.core.util.FieldWrapper;
import org.apache.ibatis.reflection.TypeParameterResolver;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;
/**
* 属性查询管理
*
* @author 王帅
* @since 2023-07-15
*/
public class FieldQueryManager {
private FieldQueryManager() {
}
public static void queryFields(BaseMapper<?> mapper, Collection<?> entities, Map<String, FieldQuery> fieldQueryMap) {
for (Object entity : entities) {
Class<?> entityClass = entity.getClass();
List<Field> allFields = ClassUtil.getAllFields(entityClass);
for (Field field : allFields) {
String mapKey = entityClass.getName() + '#' + field.getName();
FieldQuery fieldQuery = fieldQueryMap.get(mapKey);
// 属性包含对应的查询包装器
if (fieldQuery != null) {
@SuppressWarnings("unchecked")
QueryWrapper queryWrapper = fieldQuery.getQueryBuilder().build(entity);
FieldType fieldType = fieldQuery.getFieldType();
if (fieldType == FieldType.AUTO) {
fieldType = FieldType.determineFieldType(field);
}
Class<?> realFieldType = field.getType();
Object value;
switch (fieldType) {
case COLLECTION:
Class<?> genericType = getGenericType(entityClass, field);
List<?> list = mapper.selectListByQueryAs(queryWrapper, genericType);
// 转换成 Collection 子类或者空 Collection 对象避免 NPE
if (list != null) {
value = getCollectionValue(realFieldType, list);
// 循环查询泛型实体类
if ((!Number.class.isAssignableFrom(genericType)
|| !String.class.isAssignableFrom(genericType)
|| !Map.class.isAssignableFrom(genericType))
&& !fieldQuery.isPrevent()) {
queryFields(mapper, (Collection<?>) value, fieldQueryMap);
}
} else {
value = new ArrayList<>();
}
break;
case ENTITY:
value = mapper.selectOneByQueryAs(queryWrapper, realFieldType);
// 循环查询嵌套类
if (!fieldQuery.isPrevent()) {
queryFields(mapper, Collections.singletonList(value), fieldQueryMap);
}
break;
case MAP:
List<Row> rows = mapper.selectRowsByQuery(queryWrapper);
// 转换成 Map 子类或者空 Map 对象避免 NPE
if (rows != null && !rows.isEmpty() && rows.get(0) != null) {
value = getMapValue(realFieldType, rows.get(0));
} else {
value = new HashMap<>();
}
break;
case BASIC:
value = mapper.selectObjectByQueryAs(queryWrapper, realFieldType);
break;
case ARRAY:
Class<?> componentType = realFieldType.getComponentType();
List<?> objects = mapper.selectListByQueryAs(queryWrapper, componentType);
value = getArrayValue(componentType, objects);
break;
default:
value = null;
break;
}
// 属性查询出来的值不为 null 为属性设置值
if (value != null) {
FieldWrapper.of(entityClass, fieldQuery.getFieldName()).set(value, entity);
}
}
}
}
}
private static Class<?> getGenericType(Class<?> entityClass, Field field) {
Type genericType = TypeParameterResolver.resolveFieldType(field, entityClass);
if (genericType instanceof ParameterizedType) {
return (Class<?>) ((ParameterizedType) genericType).getActualTypeArguments()[0];
} else {
throw FlexExceptions.wrap("Can not resolve generic type %s in field %s", genericType, field.getName());
}
}
@SuppressWarnings({"rawtypes", "unchecked"})
private static Object getCollectionValue(Class<?> fieldType, Collection value) {
if (ClassUtil.canInstance(fieldType.getModifiers())) {
Collection collection = (Collection) ClassUtil.newInstance(fieldType);
collection.addAll(value);
return collection;
}
if (List.class.isAssignableFrom(fieldType)) {
return value;
}
if (Set.class.isAssignableFrom(fieldType)) {
return new HashSet<>(value);
}
throw FlexExceptions.wrap("Unsupported collection type.");
}
@SuppressWarnings({"rawtypes", "unchecked"})
private static Object getMapValue(Class<?> fieldType, Map value) {
if (ClassUtil.canInstance(fieldType.getModifiers())) {
Map map = (Map) ClassUtil.newInstance(fieldType);
map.putAll(value);
return map;
}
return new HashMap<>(value);
}
@SuppressWarnings("unchecked")
private static <T> Object getArrayValue(Class<?> componentType, List<T> list) {
if (CollectionUtil.isEmpty(list)) {
return Array.newInstance(componentType, 0);
}
T[] array = (T[]) Array.newInstance(componentType, list.size());
for (int rows = 0; rows < list.size(); rows++) {
array[rows] = list.get(rows);
}
return array;
}
}

View File

@ -0,0 +1,109 @@
/*
* 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.field;
import com.mybatisflex.core.util.CollectionUtil;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.Time;
import java.sql.Timestamp;
import java.time.*;
import java.time.chrono.JapaneseDate;
import java.util.Collection;
import java.util.Date;
import java.util.Map;
import java.util.Set;
/**
* 属性类型
*
* @author 王帅
* @since 2023-07-15
*/
public enum FieldType {
/**
* Map 对象
*/
MAP,
/**
* 自动推断
*/
AUTO,
/**
* 数组
*/
ARRAY,
/**
* 基本数据类型
*/
BASIC,
/**
* 实体类
*/
ENTITY,
/**
* 集合
*/
COLLECTION;
private static final Set<Class<?>> BASIC_TYPES = CollectionUtil.newHashSet(
int.class, Integer.class,
short.class, Short.class,
long.class, Long.class,
float.class, Float.class,
double.class, Double.class,
boolean.class, Boolean.class,
Date.class, java.sql.Date.class, Time.class, Timestamp.class,
Instant.class, LocalDate.class, LocalDateTime.class, LocalTime.class, OffsetDateTime.class, OffsetTime.class, ZonedDateTime.class,
Year.class, Month.class, YearMonth.class, JapaneseDate.class,
byte[].class, Byte[].class, Byte.class,
BigInteger.class, BigDecimal.class,
char.class, String.class, Character.class
);
/**
* 自动推断属性类型
*
* @param field 属性
* @return 属性类型
* @see FieldType#AUTO
*/
public static FieldType determineFieldType(Field field) {
Class<?> fieldType = field.getType();
if (Collection.class.isAssignableFrom(fieldType)) {
return COLLECTION;
} else if (Map.class.isAssignableFrom(fieldType)) {
return MAP;
} else if (fieldType.isArray()) {
return ARRAY;
} else if (BASIC_TYPES.contains(fieldType)
|| fieldType.isEnum()) {
return BASIC;
} else {
return ENTITY;
}
}
}

View File

@ -17,8 +17,19 @@ package com.mybatisflex.core.field;
import com.mybatisflex.core.query.QueryWrapper;
/**
* 属性查询条件构建
*
* @param <T> 实体类类型
*/
public interface QueryBuilder<T> {
/**
* 构建查询属性的 {@link QueryWrapper} 对象
*
* @param entity 实体类
* @return 查询条件
*/
QueryWrapper build(T entity);
}

View File

@ -42,6 +42,12 @@ public class LambdaUtil {
return PropertyNamer.methodToProperty(methodName);
}
public static <T> String getClassName(LambdaGetter<T> getter) {
SerializedLambda lambda = getSerializedLambda(getter);
String className = lambda.getImplClass();
return className.replace('/', '.');
}
public static <T> String getAliasName(LambdaGetter<T> getter, boolean withPrefix) {
QueryColumn queryColumn = getQueryColumn(getter);

View File

@ -20,6 +20,7 @@ import com.mybatisflex.core.constant.SqlConsts;
import com.mybatisflex.core.exception.FlexExceptions;
import com.mybatisflex.core.field.FieldQuery;
import com.mybatisflex.core.field.FieldQueryBuilder;
import com.mybatisflex.core.field.FieldQueryManager;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.*;
import com.mybatisflex.core.relation.RelationManager;
@ -176,41 +177,23 @@ public class MapperUtil {
}
@SuppressWarnings({"rawtypes", "unchecked"})
public static <R> void queryFields(BaseMapper<?> mapper, List<R> list, Consumer<FieldQueryBuilder<R>>[] consumers) {
if (CollectionUtil.isEmpty(list) || ArrayUtil.isEmpty(consumers) || consumers[0] == null) {
return;
}
list.forEach(entity -> {
for (Consumer<FieldQueryBuilder<R>> consumer : consumers) {
FieldQueryBuilder<R> fieldQueryBuilder = new FieldQueryBuilder<>(entity);
consumer.accept(fieldQueryBuilder);
FieldQuery fieldQuery = fieldQueryBuilder.build();
QueryWrapper childQuery = fieldQuery.getQueryWrapper();
FieldWrapper fieldWrapper = FieldWrapper.of(entity.getClass(), fieldQuery.getField());
Map<String, FieldQuery> fieldQueryMap = new HashMap<>();
for (Consumer<FieldQueryBuilder<R>> consumer : consumers) {
FieldQueryBuilder<R> fieldQueryBuilder = new FieldQueryBuilder<>();
consumer.accept(fieldQueryBuilder);
FieldQuery fieldQuery = fieldQueryBuilder.build();
String className = fieldQuery.getClassName();
String fieldName = fieldQuery.getFieldName();
String mapKey = className + '#' + fieldName;
fieldQueryMap.put(mapKey, fieldQuery);
}
Class<?> fieldType = fieldWrapper.getFieldType();
Class<?> mappingType = fieldWrapper.getMappingType();
Object value;
if (Collection.class.isAssignableFrom(fieldType)) {
value = mapper.selectListByQueryAs(childQuery, mappingType);
if (!fieldType.isAssignableFrom(value.getClass())) {
fieldType = getCollectionWrapType(fieldType);
Collection newValue = (Collection) ClassUtil.newInstance(fieldType);
newValue.addAll((Collection) value);
value = newValue;
}
} else if (fieldType.isArray()) {
value = mapper.selectListByQueryAs(childQuery, mappingType);
value = ((List<?>) value).toArray();
} else {
value = mapper.selectOneByQueryAs(childQuery, mappingType);
}
fieldWrapper.set(value, entity);
}
});
FieldQueryManager.queryFields(mapper, list, fieldQueryMap);
}

View File

@ -117,7 +117,8 @@ public class AccountTester {
Account account = new Account();
account.setId(4L);
account.setUserName("test04");
accountMapper.insertSelectiveWithPk(account);
int rows = accountMapper.insertSelectiveWithPk(account);
System.out.println(rows);
accounts = accountMapper.selectAll();
System.out.println(accounts);

View File

@ -16,11 +16,9 @@
package com.mybatisflex.test.model;
import com.mybatisflex.annotation.Column;
import com.mybatisflex.annotation.RelationManyToMany;
import java.util.List;
import java.util.Objects;
/**
* 用户信息
@ -33,7 +31,6 @@ public class UserInfo {
private Integer userId;
private String userName;
private String password;
@Column(ignore = true)
private String idNumber;
@RelationManyToMany(
@ -115,44 +112,4 @@ public class UserInfo {
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
UserInfo userInfo = (UserInfo) o;
if (!Objects.equals(userId, userInfo.userId)) {
return false;
}
if (!Objects.equals(userName, userInfo.userName)) {
return false;
}
if (!Objects.equals(password, userInfo.password)) {
return false;
}
if (!Objects.equals(idNumber, userInfo.idNumber)) {
return false;
}
if (!Objects.equals(roleList, userInfo.roleList)) {
return false;
}
return Objects.equals(orderInfoList, userInfo.orderInfoList);
}
@Override
public int hashCode() {
int result = userId != null ? userId.hashCode() : 0;
result = 31 * result + (userName != null ? userName.hashCode() : 0);
result = 31 * result + (password != null ? password.hashCode() : 0);
result = 31 * result + (idNumber != null ? idNumber.hashCode() : 0);
result = 31 * result + (roleList != null ? roleList.hashCode() : 0);
result = 31 * result + (orderInfoList != null ? orderInfoList.hashCode() : 0);
return result;
}
}

View File

@ -16,8 +16,8 @@
package com.mybatisflex.test.model;
import java.util.Collection;
import java.util.TreeSet;
import java.util.HashMap;
import java.util.Map;
/**
* 用户 VO 对象
@ -30,7 +30,9 @@ public class UserVO {
private String userId;
private String userName;
private TreeSet<Role> roleList;
// private TreeSet<Role> roleList;
// private Role[] roleList;
private HashMap<String, Object> roleList;
public String getUserId() {
return userId;
@ -48,11 +50,11 @@ public class UserVO {
this.userName = userName;
}
public Collection<Role> getRoleList() {
public Map<String, Object> getRoleList() {
return roleList;
}
public void setRoleList(TreeSet<Role> roleList) {
public void setRoleList(HashMap<String, Object> roleList) {
this.roleList = roleList;
}

View File

@ -16,6 +16,7 @@
package com.mybatisflex.test.mapper;
import com.mybatisflex.core.field.FieldType;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.test.model.*;
@ -73,6 +74,7 @@ class UserMapperTest {
List<UserVO> userVOs = userMapper.selectListByQueryAs(queryWrapper, UserVO.class,
fieldQueryBuilder -> fieldQueryBuilder
.field(UserVO::getRoleList)
.prevent(true)
.queryWrapper(user -> QueryWrapper.create()
.select()
.from(ROLE)
@ -136,6 +138,40 @@ class UserMapperTest {
userInfos.forEach(System.err::println);
}
@Test
void testComplexSelectListFields() {
List<UserInfo> userInfos = userMapper.selectListByQueryAs(QueryWrapper.create(), UserInfo.class,
c -> c.field(UserInfo::getIdNumber).fieldType(FieldType.BASIC).queryWrapper(userInfo ->
QueryWrapper.create()
.select(ID_CARD.ID_NUMBER)
.from(ID_CARD)
.where(ID_CARD.ID.eq(userInfo.getUserId()))
),
c -> c.field(UserInfo::getRoleList).prevent().queryWrapper(userInfo ->
QueryWrapper.create()
.select()
.from(ROLE.as("r"))
.leftJoin(USER_ROLE).as("ur").on(USER_ROLE.ROLE_ID.eq(ROLE.ROLE_ID))
.where(USER_ROLE.USER_ID.eq(userInfo.getUserId()))
),
c -> c.field(UserInfo::getOrderInfoList).queryWrapper(userInfo ->
QueryWrapper.create()
.select()
.from(ORDER.as("o"))
.leftJoin(USER_ORDER).as("uo").on(USER_ORDER.ORDER_ID.eq(ORDER.ORDER_ID))
.where(USER_ORDER.USER_ID.eq(userInfo.getUserId()))
),
c -> c.nestedField(OrderInfo::getGoodList).prevent().queryWrapper(orderInfo ->
QueryWrapper.create()
.select()
.from(GOOD.as("g"))
.leftJoin(ORDER_GOOD).as("og").on(ORDER_GOOD.GOOD_ID.eq(GOOD.GOOD_ID))
.where(ORDER_GOOD.ORDER_ID.eq(orderInfo.getOrderId()))
)
);
userInfos.forEach(System.err::println);
}
@Test
void testEquals() {
QueryWrapper queryWrapper1 = QueryWrapper.create()
@ -150,16 +186,48 @@ class UserMapperTest {
.leftJoin(GOOD).as("g").on(GOOD.GOOD_ID.eq(ORDER_GOOD.GOOD_ID))
.orderBy(USER.USER_ID.asc(), ROLE.ROLE_ID.asc(), ORDER.ORDER_ID.asc(), GOOD.GOOD_ID.asc());
List<UserInfo> userInfos1 = userMapper.selectListByQueryAs(queryWrapper1, UserInfo.class);
userInfos1.forEach(System.err::println);
QueryWrapper queryWrapper2 = QueryWrapper.create()
.select(USER.ALL_COLUMNS, ID_CARD.ID_NUMBER)
.from(USER.as("u"))
.leftJoin(ID_CARD).as("i").on(USER.USER_ID.eq(ID_CARD.ID));
List<UserInfo> userInfos2 = userMapper.selectListWithRelationsByQueryAs(queryWrapper2, UserInfo.class);
userInfos2.forEach(System.err::println);
Assertions.assertEquals(userInfos1, userInfos2);
List<UserInfo> userInfos3 = userMapper.selectListByQueryAs(QueryWrapper.create(), UserInfo.class,
c -> c.field(UserInfo::getIdNumber).fieldType(FieldType.BASIC).queryWrapper(userInfo ->
QueryWrapper.create()
.select(ID_CARD.ID_NUMBER)
.from(ID_CARD)
.where(ID_CARD.ID.eq(userInfo.getUserId()))
),
c -> c.field(UserInfo::getRoleList).prevent().queryWrapper(userInfo ->
QueryWrapper.create()
.select()
.from(ROLE.as("r"))
.leftJoin(USER_ROLE).as("ur").on(USER_ROLE.ROLE_ID.eq(ROLE.ROLE_ID))
.where(USER_ROLE.USER_ID.eq(userInfo.getUserId()))
.orderBy(ROLE.ROLE_ID.asc())
),
c -> c.field(UserInfo::getOrderInfoList).queryWrapper(userInfo ->
QueryWrapper.create()
.select()
.from(ORDER.as("o"))
.leftJoin(USER_ORDER).as("uo").on(USER_ORDER.ORDER_ID.eq(ORDER.ORDER_ID))
.where(USER_ORDER.USER_ID.eq(userInfo.getUserId()))
.orderBy(ORDER.ORDER_ID.asc())
),
c -> c.nestedField(OrderInfo::getGoodList).prevent().queryWrapper(orderInfo ->
QueryWrapper.create()
.select()
.from(GOOD.as("g"))
.leftJoin(ORDER_GOOD).as("og").on(ORDER_GOOD.GOOD_ID.eq(GOOD.GOOD_ID))
.where(ORDER_GOOD.ORDER_ID.eq(orderInfo.getOrderId()))
.orderBy(GOOD.GOOD_ID.asc())
)
);
Assertions.assertEquals(userInfos1.toString(), userInfos2.toString());
Assertions.assertEquals(userInfos1.toString(), userInfos3.toString());
}
@Test