jamesnuge
jamesnuge

Reputation: 81

Mybatis If statements using include properties

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?

Upvotes: 8

Views: 17569

Answers (3)

Ballsigno
Ballsigno

Reputation: 501

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>

Upvotes: 2

Quentin Piette
Quentin Piette

Reputation: 1

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

Upvotes: 0

jmad
jmad

Reputation: 360

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

Upvotes: -1

Related Questions