Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cross-mapper <include> tag resolves to the wrong SQL definition #3246

Closed
lyw0210 opened this issue Sep 25, 2024 · 4 comments
Closed

Cross-mapper <include> tag resolves to the wrong SQL definition #3246

lyw0210 opened this issue Sep 25, 2024 · 4 comments

Comments

@lyw0210
Copy link

lyw0210 commented Sep 25, 2024

MyBatis version

3.5.0 and 3.5.16

Database vendor and version

mysql 8.0.29

Test case or example project

MapperA.xml

<?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="test.com.example.MapperA">
  <sql id="Base_Column_List">
    'A'
  </sql>
  <select id="select" resultType="java.util.Map">
    select <include refid="test.com.example.MapperB.More_Column_List"/>
  </select>
</mapper>

MapperB.xml

<?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="test.com.example.MapperB">
  <sql id="Base_Column_List">
    'B'
  </sql>
  <sql id="More_Column_List">
    <include refid="Base_Column_List"/>
  </sql>
</mapper>

MapperA.class

public interface MapperA {
    Map<String, Object> select();
}

MapperB.class

public interface MapperB {
}

Steps to reproduce

run MapperA#select

Expected result

==> Preparing: select 'B'

Actual result

==> Preparing: select 'A'

@harawata
Copy link
Member

Hello @lyw0210 ,

MyBatis resolves include sequentially when it's nested.

So, this is original.

<select id="select" resultType="java.util.Map">
  select <include refid="test.com.example.MapperB.More_Column_List"/>
</select>

First step is obvious.

<select id="select" resultType="java.util.Map">
  select <include refid="Base_Column_List"/>
</select>

In the second step, refid is not fully-qualified, so it references Base_Column_List in the same mapper i.e. test.com.example.MapperA.

That example is not realistic, so it's unclear what exactly you want to achieve, but you should use fully-qualified ID or <property>.

@lyw0210
Copy link
Author

lyw0210 commented Sep 25, 2024

@harawata
The fact is, this is a simplified example of a problem I encountered in a real project. I want to reuse the <SQL> from MapperB in MapperA.
I believe the <sql id="More_Column_List"> should behave consistently in both MapperA and MapperB, so the <include> should be parsed from the inside out, right?

(Sorry, English is not my native language, so there might be some grammatical errors.)

@harawata
Copy link
Member

You English is probably better than mine. :)

It does behave consistently.
It is just parsed from the outside in, not from the inside out.

It seems to be the only possible way technically, but even if there is a way to change the behavior, it will break backward compatibility, so we can't/won't change it.

this is a simplified example of a problem I encountered in a real project

I know.
My point is, if you explain the problem, we might be able to propose another solution.
It's called XY problem.

@lyw0210
Copy link
Author

lyw0210 commented Sep 26, 2024

My English comes from ChatGPT, haha. XD

I now understand that this is the expected behavior of Mybatis, and that’s enough for me. I think I can find a better solution.

Thank you for clarifying!

harawata added a commit that referenced this issue Dec 1, 2024
Several users reported this behavior as a bug, but it is by design.
#2590 #3246 #3306
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants