Quantcast

Different behavior of PreparedStatement parameters and string substitution parameters

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Different behavior of PreparedStatement parameters and string substitution parameters

demosfen
Hello,
I've got this code in my project and it works fine:
        <insert id="insert">
                INSERT INTO ${metaInfo.tableName} (id,db_id,modified_date,
                <foreach collection="metaInfo.dictClassifiers" index="i"
separator=",">class_id_${i}</foreach>)
                VALUES (#{bean.id},#{bean.stamp.dbId},#{bean.stamp.modifiedDate},
                <foreach collection="metaInfo.dictClassifiers" item="dict"
separator=",">'${bean.classifiers[dict].id}'</foreach>)
        </insert>

I changed '${bean.classifiers[dict].id}' to
#{bean.classifiers[dict].id, jdbcType=VARCHAR} but got "ORA-01400:
cannot insert NULL into ..."CLASS_ID_0")" so it had evaluated
expression to null;

metaInfo.dictClassifiers is List<DictClassifierRead> and
bean.classifiers is Map<DictClassifierRead, ClassifierRead>.

I tried also using bean.classifiers.get(dict).id and it failed too.
Could I use such expressions and PreparedStatement binding in some
way?

Andrew Shalin
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Different behavior of PreparedStatement parameters and string substitution parameters

demosfen
I've learned MyBatis source code and I've found that for evaluating ${...} and #{...} parameters MyBatis uses different approaches. Expression in  ${...} is evaluated by Ognl evaluator and expression in #{...} is evaluated by incorporated PropertyTokenizer and reflection in MetaObject. So in #{} you could only use map with string key concatenated in expression like #{map[key1]} or list-array with index concatenated in expression like #{list[5]} or #{list[${i}]}.
I've solved my problem by adding method Classifier[] getClassifierArray() to my bean implementation and replacing
<foreach collection="metaInfo.dictClassifiers" item="dict" separator=",">'${bean.classifiers[dict].id}'</foreach> with
<foreach collection="metaInfo.dictClassifiers" item="dict" index="i" separator=",">#{bean.classifiersArray[${i}].id}</foreach>

When I searched for solution I found that <foreach> raised NullPointerException if index attribute was used and item wasn't:
Caused by: java.lang.NullPointerException
at java.util.regex.Pattern.<init>(Pattern.java:1132)
at java.util.regex.Pattern.compile(Pattern.java:823)
at java.lang.String.replaceFirst(String.java:2146)
at org.apache.ibatis.builder.xml.dynamic.ForEachSqlNode$FilteredDynamicContext$1.handleToken(ForEachSqlNode.java:134)
I think it's a bug.

I'd like to know why MyBatis uses different approaches for navigating object graph? Would Ognl evaluator be used for calculating query parameters at some time?

четверг, 22 марта 2012 г. 18:03:13 UTC+4 пользователь Andrew Shalin написал:
Hello,
I've got this code in my project and it works fine:
        <insert id="insert">
                INSERT INTO ${metaInfo.tableName} (id,db_id,modified_date,
                <foreach collection="metaInfo.dictClassifiers" index="i"
separator=",">class_id_${i}</foreach>)
                VALUES (#{bean.id},#{bean.stamp.dbId},#{bean.stamp.modifiedDate},
                <foreach collection="metaInfo.dictClassifiers" item="dict"
separator=",">'${bean.classifiers[dict].id}'</foreach>)
        </insert>

I changed '${bean.classifiers[dict].id}' to
#{bean.classifiers[dict].id, jdbcType=VARCHAR} but got "ORA-01400:
cannot insert NULL into ..."CLASS_ID_0")" so it had evaluated
expression to null;

metaInfo.dictClassifiers is List<DictClassifierRead> and
bean.classifiers is Map<DictClassifierRead, ClassifierRead>.

I tried also using bean.classifiers.get(dict).id and it failed too.
Could I use such expressions and PreparedStatement binding in some
way?

Andrew Shalin
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate
star

Re: Different behavior of PreparedStatement parameters and string substitution parameters

Dridi Boukelmoune
Hi,

I don't have the answer for the expression thing.

However I can suggest you to try this :
<foreach collection="metaInfo.dictClassifiers" item="dict"separator=",">#{dict.id}</foreach>

Since you're not using the i index, you may not need it.

Dridi

http://www.zenika.com/

Le mardi 27 mars 2012 21:46:44 UTC+2, Andrew Shalin a écrit :
I've learned MyBatis source code and I've found that for evaluating ${...} and #{...} parameters MyBatis uses different approaches. Expression in  ${...} is evaluated by Ognl evaluator and expression in #{...} is evaluated by incorporated PropertyTokenizer and reflection in MetaObject. So in #{} you could only use map with string key concatenated in expression like #{map[key1]} or list-array with index concatenated in expression like #{list[5]} or #{list[${i}]}.
I've solved my problem by adding method Classifier[] getClassifierArray() to my bean implementation and replacing
<foreach collection="metaInfo.dictClassifiers" item="dict" separator=",">'${bean.classifiers[dict].id}'</foreach> with
<foreach collection="metaInfo.dictClassifiers" item="dict" index="i" separator=",">#{bean.classifiersArray[${i}].id}</foreach>

When I searched for solution I found that <foreach> raised NullPointerException if index attribute was used and item wasn't:
Caused by: java.lang.NullPointerException
at java.util.regex.Pattern.<init>(Pattern.java:1132)
at java.util.regex.Pattern.compile(Pattern.java:823)
at java.lang.String.replaceFirst(String.java:2146)
at org.apache.ibatis.builder.xml.dynamic.ForEachSqlNode$FilteredDynamicContext$1.handleToken(ForEachSqlNode.java:134)
I think it's a bug.

I'd like to know why MyBatis uses different approaches for navigating object graph? Would Ognl evaluator be used for calculating query parameters at some time?

четверг, 22 марта 2012 г. 18:03:13 UTC+4 пользователь Andrew Shalin написал:
Hello,
I've got this code in my project and it works fine:
        <insert id="insert">
                INSERT INTO ${metaInfo.tableName} (id,db_id,modified_date,
                <foreach collection="metaInfo.dictClassifiers" index="i"
separator=",">class_id_${i}</foreach>)
                VALUES (#{bean.id},#{bean.stamp.dbId},#{bean.stamp.modifiedDate},
                <foreach collection="metaInfo.dictClassifiers" item="dict"
separator=",">'${bean.classifiers[dict].id}'</foreach>)
        </insert>

I changed '${bean.classifiers[dict].id}' to
#{bean.classifiers[dict].id, jdbcType=VARCHAR} but got "ORA-01400:
cannot insert NULL into ..."CLASS_ID_0")" so it had evaluated
expression to null;

metaInfo.dictClassifiers is List<DictClassifierRead> and
bean.classifiers is Map<DictClassifierRead, ClassifierRead>.

I tried also using bean.classifiers.get(dict).id and it failed too.
Could I use such expressions and PreparedStatement binding in some
way?

Andrew Shalin
Loading...