Skip to content

Commit f30c6cc

Browse files
committed
Fn支持直接输入字段名或列名,支持使用字符串形式的参数。
1 parent 6916377 commit f30c6cc

File tree

5 files changed

+156
-10
lines changed

5 files changed

+156
-10
lines changed

activerecord/src/test/java/io/mybatis/activerecord/spring/ActiveRecordTest.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import io.mybatis.mapper.BaseMapper;
1919
import io.mybatis.mapper.example.Example;
20+
import io.mybatis.mapper.fn.Fn;
2021
import org.junit.AfterClass;
2122
import org.junit.Assert;
2223
import org.junit.BeforeClass;
@@ -162,9 +163,33 @@ public void testUser() {
162163
@Test
163164
public void testUserExample() {
164165
User user = new User();
166+
user.save();
167+
165168
Example<User> example = user.example();
166-
example.createCriteria().andEqualTo(User::getId, 2);
169+
example.createCriteria().andEqualTo(User::getId, user.getId());
170+
Assert.assertEquals(1, user.delete(example));
171+
172+
user.setRoleId(99);
173+
user.setId(null);
174+
user.save();
175+
example = user.example();
176+
example.createCriteria().andEqualTo(Fn.field(User.class, User::getRoleId), user.getRoleId());
167177
Assert.assertEquals(1, user.delete(example));
178+
179+
user.setRoleId(99);
180+
user.setId(null);
181+
user.save();
182+
example = user.example();
183+
example.createCriteria().andEqualTo(Fn.field(User.class, "roleId"), user.getRoleId());
184+
Assert.assertEquals(1, user.delete(example));
185+
186+
user.setRoleId(99);
187+
user.setId(null);
188+
user.save();
189+
example = user.example();
190+
example.createCriteria().andEqualTo(Fn.column(User.class, "role_id"), user.getRoleId());
191+
Assert.assertEquals(1, user.delete(example));
192+
168193
String name = "example";
169194
int count = 5;
170195
user = new User(name);

mapper/src/main/java/io/mybatis/mapper/fn/Fn.java

Lines changed: 69 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,11 +35,11 @@ public interface Fn<T, R> extends Function<T, R>, Serializable {
3535
/**
3636
* 缓存方法引用和对应的列信息
3737
*/
38-
Map<Fn, EntityColumn> FN_COLUMN_MAP = new HashMap<>();
38+
Map<Fn<?, ?>, EntityColumn> FN_COLUMN_MAP = new HashMap<>();
3939
/**
4040
* 缓存方法引用和对应的字段信息
4141
*/
42-
Map<Fn, Reflections.ClassField> FN_CLASS_FIELD_MAP = new HashMap<>();
42+
Map<Fn<?, ?>, Reflections.ClassField> FN_CLASS_FIELD_MAP = new HashMap<>();
4343

4444
/**
4545
* 指定字段集合的虚拟表,当通过基类或者泛型基类获取字段时,需要设置字段所属的实体类
@@ -48,6 +48,7 @@ public interface Fn<T, R> extends Function<T, R>, Serializable {
4848
* @param fns 指定字段
4949
* @return 虚拟表
5050
*/
51+
@SafeVarargs
5152
static <E> Fns<E> of(Class<E> entityClass, Fn<E, Object>... fns) {
5253
return new Fns<>(entityClass, fns);
5354
}
@@ -58,6 +59,7 @@ static <E> Fns<E> of(Class<E> entityClass, Fn<E, Object>... fns) {
5859
* @param fns 指定字段
5960
* @return 虚拟表
6061
*/
62+
@SafeVarargs
6163
static <E> Fns<E> of(Fn<E, Object>... fns) {
6264
return of(null, fns);
6365
}
@@ -72,11 +74,40 @@ static <E> Fns<E> of(Fn<E, Object>... fns) {
7274
static <E> Fns<E> of(Class<E> entityClass, String... columnNames) {
7375
EntityTable entityTable = EntityFactory.create(entityClass);
7476
Set<String> columnNameSet = Arrays.stream(columnNames).collect(Collectors.toSet());
75-
List<EntityColumn> columns = entityTable.columns().stream()
76-
.filter(column -> columnNameSet.contains(column.property())).collect(Collectors.toList());
77+
List<EntityColumn> columns = entityTable.columns().stream().filter(column -> columnNameSet.contains(column.property())).collect(Collectors.toList());
7778
return new Fns<>(entityClass, entityTable.tableName(), columns);
7879
}
7980

81+
/**
82+
* 指定类中字段名
83+
*
84+
* @param entityClass 字段所属实体类
85+
* @param field 实体类中的字段名
86+
*/
87+
static <T> Fn<T, Object> field(Class<T> entityClass, Fn<T, Object> field) {
88+
return field.in(entityClass);
89+
}
90+
91+
/**
92+
* 通过字符串形式指定(类中)字段名
93+
*
94+
* @param entityClass 字段所属实体类
95+
* @param field 实体类中的字段名
96+
*/
97+
static <T> Fn<T, Object> field(Class<T> entityClass, String field) {
98+
return new FnName<>(entityClass, field);
99+
}
100+
101+
/**
102+
* 通过字符串形式指定(表中的)列名
103+
*
104+
* @param entityClass 字段所属实体类
105+
* @param column 实体类对应表中的列名
106+
*/
107+
static <T> Fn<T, Object> column(Class<T> entityClass, String column) {
108+
return new FnName<>(entityClass, column, true);
109+
}
110+
80111
/**
81112
* 当前字段所属的实体类,当实体存在继承关系时
82113
* 父类的方法引用无法获取字段所属的实体类,需要通过该方法指定
@@ -137,9 +168,7 @@ default EntityColumn toEntityColumn() {
137168
// 先区分大小写匹配字段
138169
.filter(column -> column.property().equals(classField.getField())).findFirst()
139170
// 如果不存在,再忽略大小写进行匹配
140-
.orElseGet(() -> columns.stream().filter(column -> column.property().equalsIgnoreCase(classField.getField()))
141-
.findFirst().orElseThrow(() -> new RuntimeException(classField.getField()
142-
+ " does not mark database column field annotations, unable to obtain column information")));
171+
.orElseGet(() -> columns.stream().filter(classField).findFirst().orElseThrow(() -> new RuntimeException(classField.getField() + " does not mark database column field annotations, unable to obtain column information")));
143172
FN_COLUMN_MAP.put(this, entityColumn);
144173
}
145174
}
@@ -167,6 +196,38 @@ public R apply(T t) {
167196

168197
}
169198

199+
/**
200+
* 间接支持直接指定字段名或列名,避免只能通过方法引用使用
201+
*/
202+
class FnName<T, R> implements Fn<T, R> {
203+
final Class<?> entityClass;
204+
final String name;
205+
/**
206+
* false代表name为字段,true代表name值为列
207+
*/
208+
final boolean column;
209+
210+
public FnName(Class<?> entityClass, String name, boolean column) {
211+
this.entityClass = entityClass;
212+
this.name = name;
213+
this.column = column;
214+
}
215+
216+
public FnName(Class<?> entityClass, String name) {
217+
this(entityClass, name, false);
218+
}
219+
220+
@Override
221+
public Fn<T, R> in(Class<?> entityClass) {
222+
return new FnName<>(entityClass, this.name, this.column);
223+
}
224+
225+
@Override
226+
public R apply(Object o) {
227+
return null;
228+
}
229+
}
230+
170231
/**
171232
* 字段数组,用于获取字段对应的所有字段名和列名,当前对象相当于一个部分字段的虚拟表
172233
*
@@ -192,6 +253,7 @@ private Fns(Class<E> entityClass, String table, List<EntityColumn> columns) {
192253
*
193254
* @param fns 字段数组
194255
*/
256+
@SafeVarargs
195257
private Fns(Class<E> entityClass, Fn<E, Object>... fns) {
196258
super(entityClass);
197259
this.columns = new ArrayList<>(fns.length);

mapper/src/main/java/io/mybatis/mapper/fn/Reflections.java

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@
1616

1717
package io.mybatis.mapper.fn;
1818

19+
import io.mybatis.provider.EntityColumn;
20+
1921
import java.beans.Introspector;
2022
import java.lang.invoke.SerializedLambda;
2123
import java.lang.reflect.Method;
24+
import java.util.function.Predicate;
2225
import java.util.regex.Matcher;
2326
import java.util.regex.Pattern;
2427

@@ -36,9 +39,19 @@ public class Reflections {
3639
private Reflections() {
3740
}
3841

39-
public static ClassField fnToFieldName(Fn fn) {
42+
public static ClassField fnToFieldName(Fn<?, ?> fn) {
4043
try {
4144
Class<?> clazz = null;
45+
//支持直接指定的字段名
46+
if (fn instanceof Fn.FnName) {
47+
Fn.FnName<?, ?> field = (Fn.FnName<?, ?>) fn;
48+
if (field.column) {
49+
return new ClassColumn(field.entityClass, field.name);
50+
} else {
51+
return new ClassField(field.entityClass, field.name);
52+
}
53+
}
54+
//支持指定实体类
4255
if (fn instanceof Fn.FnImpl) {
4356
clazz = ((Fn.FnImpl<?, ?>) fn).entityClass;
4457
fn = ((Fn.FnImpl<?, ?>) fn).fn;
@@ -74,7 +87,10 @@ public static ClassField fnToFieldName(Fn fn) {
7487
}
7588
}
7689

77-
public static class ClassField {
90+
/**
91+
* 记录字段对应的类和字段名
92+
*/
93+
public static class ClassField implements Predicate<EntityColumn> {
7894
private final Class<?> clazz;
7995
private final String field;
8096

@@ -83,6 +99,11 @@ public ClassField(Class<?> clazz, String field) {
8399
this.field = field;
84100
}
85101

102+
@Override
103+
public boolean test(EntityColumn column) {
104+
return getField().equalsIgnoreCase(column.property());
105+
}
106+
86107
public Class<?> getClazz() {
87108
return clazz;
88109
}
@@ -91,4 +112,19 @@ public String getField() {
91112
return field;
92113
}
93114
}
115+
116+
/**
117+
* 记录字段对应的类和列名
118+
*/
119+
public static class ClassColumn extends ClassField {
120+
121+
public ClassColumn(Class<?> clazz, String field) {
122+
super(clazz, field);
123+
}
124+
125+
@Override
126+
public boolean test(EntityColumn column) {
127+
return getField().equalsIgnoreCase(column.column());
128+
}
129+
}
94130
}

mapper/src/test/java/io/mybatis/mapper/fn/FnTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,10 @@ public void test() {
3333
Assert.assertEquals("name", ((Fn<User, Object>) User::getUserName).toColumn());
3434
Assert.assertEquals("admin", ((Fn<UserIs, Object>) UserIs::isAdmin).toField());
3535
Assert.assertEquals("is_admin", ((Fn<UserIs, Object>) UserIs::isAdmin).toColumn());
36+
37+
Assert.assertEquals("is_admin", Fn.field(UserIs.class, UserIs::isAdmin).toColumn());
38+
Assert.assertEquals("is_admin", Fn.field(UserIs.class, "admin").toColumn());
39+
Assert.assertEquals("is_admin", Fn.column(UserIs.class, "is_admin").toColumn());
3640
}
3741

3842
@Test
@@ -50,6 +54,11 @@ public void testExtends() {
5054
Assert.assertEquals("when_create", ((Fn<SysRole, Object>) SysRole::getWhenCreate).toColumn());
5155
Assert.assertEquals("roleName", ((Fn<SysRole, Object>) SysRole::getRoleName).toField());
5256
Assert.assertEquals("name", ((Fn<SysRole, Object>) SysRole::getRoleName).toColumn());
57+
58+
59+
Assert.assertEquals("when_create", Fn.field(SysRole.class, BaseEntity::getWhenCreate).toColumn());
60+
Assert.assertEquals("when_create", Fn.field(SysRole.class, "whenCreate").toColumn());
61+
Assert.assertEquals("when_create", Fn.column(SysRole.class, "when_create").toColumn());
5362
}
5463

5564
public static class BaseId {

mapper/src/test/java/io/mybatis/mapper/fn/UserIdsFnMapperTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,20 @@ public void testSelectColumns() {
7676
Assert.assertNull(u.getId2());
7777
Assert.assertNotNull(u.getName());
7878
});
79+
80+
users = mapper.selectColumns(user, Fn.of(UserIds::getId1, UserIds::getName));
81+
users.forEach(u -> {
82+
Assert.assertNotNull(u.getId1());
83+
Assert.assertNull(u.getId2());
84+
Assert.assertNotNull(u.getName());
85+
});
86+
87+
users = mapper.selectColumns(user, Fn.of(UserIds.class, "id1", "name"));
88+
users.forEach(u -> {
89+
Assert.assertNotNull(u.getId1());
90+
Assert.assertNull(u.getId2());
91+
Assert.assertNotNull(u.getName());
92+
});
7993
} finally {
8094
//不要忘记关闭sqlSession
8195
sqlSession.close();

0 commit comments

Comments
 (0)