Mybatis If statements using include properties
Asked Answered
P

3

8

I'm trying to create a generic SQL include in Mybatis that will apply a comparator given a particular value. The idea is to reuse this sql code snippet across several mappers. The issue I'm having is when using string substitution in the if statement inside of my include.

Currently the xml looks like this:

<select id="get" parameterType="ServiceModelQueryHelper" resultMap="ServiceRecordMap">
    SELECT * from service
    <if test="name.isApplicable()">
        WHERE service.name
        <include refid=comparatorMapper>
            <property name="comparator" value="${name.comparator}"/>
            <property name="value" value="${name.value}"/>
        </include>
    </if>
</select>
<sql id="comparatorMapper">
    <if test="${comparator} == 'EQUALS'">
        = ${value}
    </if>
    <if test="${comparator} == 'CONTAINS'">
        ~ ${value}
    </if>
</sql>

When using the ${comparator} inside of the test the OGNL expression is evaluated before the string substitution occures causing a ParseException because $ is not a valid first character.

Is there a way to reference a property of an sql snippet inside of an OGNL expression?

Porta answered 8/2, 2016 at 5:30 Comment(2)
I think you should use the parameter marker #{comparator} instead of the string substitution.Diestock
I tried using #{comparator} but this makes mybatis look for a comparator field on the ServiceModelQueryHelper in the parent query, rather than on the object passed in to the include statementPorta
D
2

Haha, I have the same problem now, but I found out the way.
That is to use bind. I know I no longer can't call property in that way.

<bind name="isGetList" value='"1"' />
<include refid="conditionSql" />

<sql id="conditionSql">
    <if test='isGetList == "1"'>
        for example.
    </if>
</sql>
Daryl answered 2/8, 2018 at 1:53 Comment(0)
L
0

I found a dirty way to do the job :

You add an object that will contain your parameter in ServiceModelQueryHelper, you can then set your parameter inside a if statement

Ex :

public class ServiceModelQueryHelper {
    private ContainerForGenericSql containerForGenericSql = new ContainerForGenericSql();
    ...
}

public class ContainerForGenericSql {

    private String parameterForGenericSql;

    public String getParameterForGenericSql() {
    return parameterForGenericSql;
    }

    public void setParameterForGenericSql(
        String parameterForGenericSql) {
    this.parameterForGenericSql = parameterForGenericSql;
    }

    public boolean setParameterForGenericSqlAndReturnTrue(
        String parameterForGenericSql) {
        this.parameterForGenericSql = parameterForGenericSql;
        return true;
    }
}

<select id="get" parameterType="ServiceModelQueryHelper" resultMap="ServiceRecordMap">
    SELECT * from service
    <if test="name.isApplicable()">
        WHERE service.name
        <if test="containerForGenericSql.setParameterForGenericSqlAndReturnTrue(name.comparator)">
        </if>
        <include refid=comparatorMapper>
            <property name="value" value="${name.value}"/>
        </include>
    </if>
</select>
<sql id="comparatorMapper">
    <if test="containerForGenericSql.parameterForGenericSql == 'EQUALS'">
        = ${value}
    </if>
    <if test="containerForGenericSql.parameterForGenericSql == 'CONTAINS'">
        ~ ${value}
    </if>
</sql>

parameterForGenericSql can also be a complex type and you can use it in IF statement, it can also be a list that you can use in FOREACH statement.

It's the only way I found to create generic SQL include that can use parameters in IF and FOREACH

Lock answered 27/4, 2017 at 9:3 Comment(0)
H
-1

Take a look at mybatis docs. The conditional statements don´t require #,$ style references.

Hera answered 11/2, 2016 at 9:19 Comment(1)
I know that conditional statements don't require the style references, but to use passed in properties in an include you need to use the $ notation. Not using those notations causes the query to look on the parent object again, which in my opinion defeats the purpose of passing in properties (if you want to use dynamic sql in an include)Porta

© 2022 - 2024 — McMap. All rights reserved.