1

This is my first question here, so please let me know if there's anything I can provide to make my question clearer. Thanks!

Is there anyway to tweak MyBatis (3.0.4) so that when it's running through the nested result maps and creating objects based on the results, it doesn't create "duplicate" objects and instead references the object that has already been created? To clarify, let's say I've got an object that consists of the following (simplified) info:

Public class PrimaryObject {
    Private Contact role1;
    Private Contact role2;
    Private List<OtherObject> otherObjects;
}  

Public class OtherObject {
    Private String otherProperty;
    Private Contact otherRole;
}

And the result maps/SQL (assume type aliases):

<mapper namespace="PrimaryObject">
    <resultMap id="primaryObject" type="primaryObject">
        <association property="role1" column="ROLE_1_ID"
         select="Contact.findContactByPK" />
        <association property="role2" column="ROLE_2_ID"
         select="Contact.findContactByPK" />
        <collection property="otherObjects" column="PRIMARY_OBJECT_ID"
         javaType="List" ofType="OtherObject"
         select="OtherObject.findOtherObjectsByPrimaryObjectPK" />
    </resultMap>
    <select id="selectPrimaryObjectByPK" parameterType="..."
     resultMap="primaryObject">
        SELECT * FROM PRIMARY_OBJECT_TABLE
        WHERE PRIMARY_OBJECT_ID = #{value}
    </select>

...

<mapper namespace="OtherObject">
    <resultMap id="otherObject" type="otherObject">
        <result property="otherProperty" column="OTHER_PROPERTY" />
        <association property="otherRole" column="OTHER_ROLE_ID"
         select="Contact.findContactByPK" />
    </resultMap>
    <select id="findOtherObjectsByPrimaryObjectPK" parameterType="..."
     resultMap="otherObject">
        SELECT OTHER_OBJECT.OTHER_PROPERTY, OTHER_OBJECT.OTHER_ROLE_ID
        FROM OTHER_OBJECT JOIN PRIMARY_OBJECT
            ON PRIMARY_OBJECT.PRIMARY_OBJECT_ID = OTHER_OBJECT.PRIMARY_OBJECT_ID
    </select>

...

<mapper namespace="Contact">
    <resultMap id="contact" type="Contact">
        <result property...
        ...
    </resultMap>
    <select id="findContactByPK" parameterType="..." resultMap="contact">
        SELECT * FROM CONTACT...
    </select>

Now let's say a contact is acting as both role1 and role2 on primaryObject. From what I've seen, MyBatis creates the contact object referenced in role1, and when it hits role2, it simply references the object it created for role1. That's great!

However, let's say that same contact is acting as the otherRole in otherObject. MyBatis now creates an identical contact object, as opposed to just referencing the original contact created/referenced when making the primaryObject. Is there any way I can prevent this from happening, and instead just store a reference in my otherObject that references that same contact that the two different fields in primaryObject are pointing to? I've been looking at a custom ResultHandler, but the example's complexity coupled with my lack of experience is preventing me from understanding if it even addresses the problem I'm trying to solve in the first place. Thanks in advance for your help and patience!

molo
  • 11
  • 2
  • Welcome to stack overflow! I think your question is pretty good. If you haven't stumbled across it already, I recommend reading the FAQ, http://stackoverflow.com/faq. – Andy Nov 07 '11 at 03:52

1 Answers1

0

OK, I think your question might be a duplicate of How to map a myBatis result to multiple objects?. So, no MyBatis does not have native support for this problem, if I'm understanding it correctly.

You should be careful using nested selects, as they execute addition select statements on the database. I suggest checking out the MyBatis 3 User Guide, particularly around page 35 and up. MyBatis has very powerful ways to avoid the n+1 selects problem. What is SELECT N+1?

Community
  • 1
  • 1
Andy
  • 8,841
  • 8
  • 45
  • 68
  • 1
    Thanks for the info! My question is very similar to the one posted by @holic87, but I'm more concerned about preventing new objects from getting instantiated _before_ the resultset is made as opposed to manipulating the objects afterwards. I think this might be possible with plugins and I'm working through some ideas right now. I'll be sure to update the question if I stumble across anything. Thanks again! – molo Nov 07 '11 at 18:03