mybatis-mapper / mapper

MyBatis Mapper
https://mapper.mybatis.io
Apache License 2.0
325 stars 47 forks source link

Example 系列方法 支持拼接单层级的 OR 条件 #17

Closed ydq closed 2 years ago

ydq commented 2 years ago

尝试性的支持 https://github.com/mybatis-mapper/mapper/issues/15 单层级(不支持 andOr() 条件里面 继续嵌套更细粒度的 andOr() )的 or 条件拼接

//example:
UserMapper2 mapper = sqlSession.getMapper(UserMapper2.class);
Example<User> example = mapper.example();
example.createCriteria()
        .andEqualTo(User::getSex,"男")
        .andOr(example.orPart()
                        .andLike(User::getUserName,"杨%"),
                example.orPart()
                        .andLike(User::getUserName,"俞%")
                        .andLike(User::getUserName,"%舟"));

输出SQL(支持 select 和 update):

xxx WHERE ( sex = ? AND ( ( name LIKE ? ) OR ( name LIKE ? AND name LIKE ? ) ) )
abel533 commented 2 years ago

感谢参与,感谢PR。

如果你有时间,可以看看 example-entityclass 分支,Example 目前还有一个涉及根本的问题,可以一起看看如何可以设计的更好。

上面这个问题和 https://github.com/mybatis-mapper/mapper/issues/11 这儿有关。 主要是通过方法引用获取字段时,得到的不是子类,而且声明方法所在的类(如果有法拿到子类是最好的解决办法)。 临时解决方法是把父类也加Entity 注解,当成独立的实体来使用。 上面这个分支是临时写的,和tk.mapper中类似,需要提供Example对应的实体类,后续在获取字段后,从实体类中筛选字段对应的信息(这个分支还没改到这里)

ydq commented 2 years ago

感谢参与,感谢PR。

如果你有时间,可以看看 example-entityclass 分支,Example 目前还有一个涉及根本的问题,可以一起看看如何可以设计的更好。

上面这个问题和 #11 这儿有关。 主要是通过方法引用获取字段时,得到的不是子类,而且声明方法所在的类(如果有法拿到子类是最好的解决办法)。 临时解决方法是把父类也加Entity 注解,当成独立的实体来使用。 上面这个分支是临时写的,和tk.mapper中类似,需要提供Example对应的实体类,后续在获取字段后,从实体类中筛选字段对应的信息(这个分支还没改到这里)

@abel533 好像可以拿得到子类:

//Reflections
public static ClassField fnToFieldName(Fn fn) {
    try {
        Method method = fn.getClass().getDeclaredMethod("writeReplace");
        method.setAccessible(Boolean.TRUE);
        SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn);
        String getter = serializedLambda.getImplMethodName();
        if (GET_PATTERN.matcher(getter).matches()) {
            getter = getter.substring(3);
        } else if (IS_PATTERN.matcher(getter).matches()) {
            getter = getter.substring(2);
        }
        String field = Introspector.decapitalize(getter);

        Pattern compile = Pattern.compile("\\(L(?<cls>.+);\\).+");
        //主要是这里  serializedLambda.getInstantiatedMethodType()
        Matcher matcher = compile.matcher(serializedLambda.getInstantiatedMethodType());
        String implClass;
        if (matcher.find()) {
            implClass = matcher.group("cls").replaceAll("/", "\\.");
        } else {
            implClass = serializedLambda.getImplClass().replaceAll("/", "\\.");
        }
        Class<?> clazz = Class.forName(implClass);
        return new ClassField(clazz, field);
    } catch (ReflectiveOperationException e) {
        throw new RuntimeException(e);
    }
}
//test case:Parent 中有个 field字段,三个子类 Child / Child2 / Child3 没有任何字段,其中Child3 还是一个内部类
Fn<Child, String> getField = Parent::getField;

Fn<Child, String> getField1 = Child::getField;

Fn<Child2, String> getField2 = Child2::getField;

Fn<Parent.Child3, String> getField3 = Parent::getField;

System.out.println(Reflections.fnToFieldName(getField).getClazz());

System.out.println(Reflections.fnToFieldName(getField1).getClazz());

System.out.println(Reflections.fnToFieldName(getField2).getClazz());

System.out.println(Reflections.fnToFieldName(getField3).getClazz());
# 输出结果
class work.darren.test.Child
class work.darren.test.Child
class work.darren.test.Child2
class work.darren.test.Parent$Child3

没在 mapper 中做具体的尝试哈,目前看这样是可行的,试过了oracle jdk8 和 jdk17

abel533 commented 2 years ago

定个闹钟,今晚看看所有代码。。