MyBatis - как создать динамическое предложение WHERE

Сервис получает неизвестный объект, содержащий список из трех значений [столбец, оператор, значение] Например, EMAIL - типа - "ТЕСТ"

На основе полученного списка построить предложение WHERE, которое у меня есть, но я также смогу построить такое условие следующим образом (например)

ГДЕ (электронная почта типа «тест» И user_id ‹> 5) ИЛИ (trans_id ‹100 И session_id> 500)

Кто-нибудь может мне помочь, как это сделать?


person tomaszd    schedule 19.05.2011    source источник


Ответы (2)


Я сам заново открывал для себя MyBatis после долгого отсутствия (одно время был знаком с iBatis). Пример Рольфа выглядит так, как будто это может быть реализация .Net, я могу ошибаться, но я не думаю, что нотация Java сейчас выглядит так. Совет Рольфа о литеральных строках очень полезен.

Я создал небольшой класс для хранения ваших столбцов, операторов и значений и передаю их в MyBatis для выполнения обработки. Столбцы и операторы являются строковыми литералами, но я оставил значения в качестве параметров sql (я полагаю, что MyBatis сможет выполнить любое необходимое преобразование типов).

public class TestAnswer {
    public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            SqlSessionFactory sqlFactory = (SqlSessionFactory) ctx.getBean("sqlSessionFactory");            
            MappedStatement statement = sqlFactory.getConfiguration().getMappedStatement("testAnswer");                        

            ArrayList<Clause> params1 = new ArrayList<Clause>();
            params1.add(new Clause("email","like","test"));
            params1.add(new Clause("user","<>",5));

            ArrayList<Clause> params2 = new ArrayList<Clause>();
            params2.add(new Clause("trans_id","<",100));
            params2.add(new Clause("session_id",">",500));

            HashMap params = new HashMap();
            params.put("params1", params1);
            params.put("params2", params2);

            BoundSql boundSql = statement.getBoundSql(params);
            System.out.println(boundSql.getSql());             
    }

    static class Clause{        
        private String column;
        private String operator;
        private Object value;

        public Clause(String column, String operator, Object value){
            this.column = column;
            this.operator = operator;
            this.value = value;
        }

        public void setColumn(String column) {this.column = column;}
        public void setOperator(String operator) {this.operator = operator;}
        public void setValue(Object value) {this.value = value;}
        public String getColumn() {return column;}
        public String getOperator() {return operator;}
        public Object getValue() {return value;}        
    }    
}

Как видите, я использую Spring, но ожидаю, что что-то подобное, вероятно, будет работать вне среды Spring.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" 
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

    <mapper namespace="com.stackoverflow.TestMapper">

    <select id="testAnswer" parameterType="map" resultType="hashmap">
      select *
    FROM somewhere
        <where>
            <foreach item="clause" collection="params1" separator=" AND " open="(" close=")"> 
                ${clause.column} ${clause.operator} #{clause.value} 
            </foreach>            
            OR
            <foreach item="clause" collection="params2" separator=" AND " open="(" close=")"> 
                ${clause.column} ${clause.operator} #{clause.value} 
            </foreach>    
        </where>
    </select>

</mapper>
person Mark McLaren    schedule 26.09.2011
comment
Для этого потребуется предложение с 4 аргументами (столбец, оператор, значение1, значение2) или, по крайней мере, какой-то способ превратить ваши 2 даты в подходящее значение. Возможно, создайте класс BetweenClause. Боюсь, это не особенно элегантное решение, поскольку форматирование даты (для поля значения) может легко стать специфичным для поставщика базы данных, если вы не пойдете на особые меры, чтобы придерживаться стандартов ANSI. - person Mark McLaren; 04.12.2013
comment
Было бы проще реализовать МЕЖДУ с помощью двух предложений SQL... stackoverflow. com/questions/4809083/между пунктами и - person Mark McLaren; 04.12.2013
comment
Привет, Марк ... Я реализовал так же, как и предложение с 4 аргументами ... Спасибо за ваш вклад в это !!! - person Krithika Vittal; 09.12.2013

В этом ответе есть две ключевые части. Один из них — «динамический», а другой — литеральные элементы $$ вокруг «оператора» в вашем вопросе.

  <select id="yourSelect" parameterClass="Map" resultMap="somethingsomething" >
    select * from YOURTABLE
      <dynamic prepend="WHERE">
        <isNotNull prepend="AND" property="email">
          email $operator$ #testvalue#
        </isNotNull>
      </dynamic>
  </select>

См. также документацию DataMapper Dynamic SQL по этой теме.

person Rolf    schedule 01.07.2011
comment
Я полагал, что это подход iBatis, он неприменим для myBatis. - person BlackMamba; 15.06.2020