Circular reverences in iBatis

2019-08-12 17:03发布

问题:

I have two classes:

class Apple {
   Worm worm;
}

class Worm {
   Apple apple;
}

They are stored in db in 1:1 fashion:

table Apple(id, wormId)
table Worm(id)

Each apple has only one worm and vice versa.

With out of iBatis I can do it simply:

Worm worm = new Worm();
Apple apple = new Apple();
worm.setApple(apple);
apple.setWorm(worm);

How can I do it in ibatis?

 <resultMap id="Apple" type="Apple">
    <result property="id" column="id"/>
    <result property="worm" column="id" select="getWormByApple"/>
 </resultMap>

 <resultMap id="Worm" type="Worm">
    <result property="id" column="id"/>
    <result property="apple" column="id" select="getAppleByWorm"/>
 </resultMap>


<select id="getApple" resultMap="Apple" parameterClass="java.lang.Long">
SELECT * FROM Apples where id=#value#
</select>

<select id="getWormByApple" resultMap="Worm" parameterClass="java.lang.Long">
SELECT * FROM Worms where appleId=#value#
</select>

So, I want to be able to do:

Apple apple = foo.queryForObject("getApple", 42L);
Worm = worm.getApple();
Apple appleAgain = apple.getWorm().getApple();
// apple == appleAgain here

Instead, I get StackOverFlowException because struts calls getWormByApple / getApple forever.

I see only one solution here:

 class Apple {
   void setWorm(Worm worm){
    this.worm = worm;
    worm.setApple(this);
   }

...and remove "property="apple"" from Worm resultMap.

But it sucks because I would have to remember which setters update argument and with is not. It also bad because may lead to infinite loop in case when Worm's setter would change argument.

I also do not want to "fix" iBatis leaks with my model classes (i.e. I do not want to touch my model beans at all).

It would be nice to have some kind of "post processor":

<resultMap id="Apple" type="Apple">
    <result property="id" column="id"/>
    <result property="worm"  select="getWormByApple"/>
    <result property="worm.apple" postProcessor="appleToWormSetter"/>
 </resultMap>

but there is no any in iBatis.

How can I solve it? Thanks

回答1:

MyBatis solves circular references automatically. Try this:

<select id="x" resultMap="appleResult">
select apple.id, worm.id from apple join worm on apple.worm_id = worm.id
</select>

And two result maps like these:

<resultMap id="appleResult" type="Apple">
  <id column="apple.id" property="id"/>
  <association property="worm" resultMap="wormResult">
</resultMap>
<resultMap id="wormResult" type="Worm">
  <id column="worm.id" property="id"/>
  <association property="apple" resultMap="appleResult">
</resultMap>

Note that in this case MyBatis will detect the cycle and link both objects together.