Динамический блок where в MyBatis

Написано 13 Февраль, 2015 в категории Java,Oracle,Разработка ПО


Динамический sql позволяет формировать запрос в зависимости от значения входных параметров. Для этого mybatis содержит условные конструкции и ряд вспомогательных конструкций для упрощения процесса программирования динамических запросов. Одной из таких вспомогательных конструкция является элемент <where>. Для понимания зачем он нужен рассмотрим пример:

<select id="searchCourses" parameterType="hashmap" resultMap="CourseResult">
    SELECT * FROM COURSES
    WHERE
        <if test=" tutorId != null ">
            TUTOR_ID= #{tutorId}
        </if>
        <if test="courseName != null">
            AND name like #{courseName}
        </if>
        <if test="startDate != null">
            AND start_date &gt;= #{startDate}
        </if>
        <if test="endDate != null">
            AND end_date &lt;= #{endDate}
        </if>
</select>

Этот код будет работать равно до того момента пока hashmap['tutorId'] не равен null. Если возникнет ситуация когда hashmap['tutorId'] окажется равным null то будет сгенерирован некорректный sql-код вне зависимости от значения остальных параметров.

Например итоговый sql - может стать таким:
Пример 1.

    SELECT * FROM COURSES
    WHERE AND name LIKE 'Java course'

тут очевидно будет лишним оператор AND
Запрос может получится таким:
Пример 2.

    SELECT * FROM COURSES
    WHERE

если все входные параметры будут иметь значение null.

из данной ситуации есть 3 выхода:

1. Для первого примера: проверять были ли проинициализированы предыдущие параметры. Естественно это приведет не только к увеличению количества вложенных условных блоков, но и проблемы в отладке при внесении изменений в динамические sql. Для второго примера можно проверять то, что хотя бы один из входных параметров удовлетворяет описанным в блоке where условиям, т.е. фактически надо продублировать все проверки блока where.
2. Использовать фиктивное условие "1=1", например так:

<select id="searchCourses" parameterType="hashmap" resultMap="CourseResult">
    SELECT * FROM COURSES
    WHERE 1=1
        <if test=" tutorId != null ">
            AND TUTOR_ID= #{tutorId}
        </if>
        <if test="courseName != null">
            AND name like #{courseName}
        </if>
        <if test="startDate != null">
            AND start_date &gt;= #{startDate}
        </if>
        <if test="endDate != null">
            AND end_date &lt;= #{endDate}
        </if>
</select>

3. Использовать элемент <where>. В случае если в, приведенном в начале поста, примере все входные параметры окажутся равны null то ключевое слово where просто не будет добавлено в sql-выражение. В случае если сразу после where будет стоять AND или OR, то на стадии формирования sql-запроса mybatis удалит эти лишние логические операторы.

<select id="searchCourses" parameterType="hashmap" resultMap="CourseResult">
    SELECT * FROM COURSES
    <where>
        <if test=" tutorId != null ">
            TUTOR_ID= #{tutorId}
        </if>
        <if test="courseName != null">
            AND name like #{courseName}
        </if>
        <if test="startDate != null">
            AND start_date &gt;= #{startDate}
        </if>
        <if test="endDate != null">
            AND end_date &lt;= #{endDate}
        </if>
    </where>
</select>