You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user-java@ibatis.apache.org by Carlos Pita <ca...@gmail.com> on 2009/12/16 17:45:03 UTC

Lazy loading differences between ibatis 2 and 3

Hi all,

I've the following sqlmap for ibatis 2. Suppose ibatis has its
lazy-loading feature enabled and I obtain a user U by means of
findUserById. Then I call U.getEmail() and findMemberById is not
executed. That's fine, one wouldn't expect the associated member to be
loaded until there is a real need for it. Of course, if then I call
U.getMember().getDescription() findMemberById does execute its select,
in due time. That said, for ibatis 3 the same example executes
findMemberById as soon as U.getEmail() is invoked, loading the member
before time. That's not surprising if one inspects the code of
ResultObjectProxy (relevant parts copied below). Is this intended to
work the way it does or is it a bug?

<sqlMap namespace="User">

	<resultMap id="userMap" class="User">
        <result property="email" column="email"/>
        <result property="member" column="member_id" select="findMemberById"/>
	</resultMap>

	<resultMap id="memberMap" class="Member">
        <result property="description" column="description"/>
	</resultMap>

	<select id="findUserById" resultMap="userMap">
		select * from qpoint_user where id = #id#
	</select>

	<select id="findMemberById" resultMap="memberMap">
		select * from cpp_member where member_id = #id#
	</select>

</sqlMap>


public class ResultObjectProxy {

   public Object invoke(Object o, Method method, Object[] args) throws
Throwable {
      try {
        if (!Object.class.equals(method.getDeclaringClass()) &&
PropertyNamer.isGetter(method.getName())) {
            lazyLoader.loadAll(); <-- this loads all asociations for
every getter invoked on this proxy
        }
        return method.invoke(target, args);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    }
}

Regards
--
Bardamu

---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
For additional commands, e-mail: user-java-help@ibatis.apache.org


Re: Lazy loading differences between ibatis 2 and 3

Posted by Clinton Begin <cl...@gmail.com>.
Carlos,

We implemented it this way to handle issues with circular
dependencies.  Essentially, yes, all dependencies will be loaded if
you access any of them.

If your getName() getter method accessed the "boss" field internally,
it would fail.

Clinton

On Wed, Dec 16, 2009 at 10:16 AM, Carlos Pita <ca...@gmail.com> wrote:
> Hi Christian,
>
> I understand your point but I don't get its relation to my question at
> all. Continuing your example, I would ask why employee.getName() will
> prematurely load the boss. A priori, I would expect the proxy to be
> smarter and only trigger the loading of boss if getBoss() was
> effectively called.
>
> Regards
> --
> Bardamu
>
> On Wed, Dec 16, 2009 at 3:09 PM, Poitras Christian
> <Ch...@ircm.qc.ca> wrote:
>> Hi,
>>
>> The major problem that was present in iBATIS 2 was that lazy loaded class where not always of the right type.
>> For exemple, if I have multiple subclasses of a class.
>> Person
>> Employee inherits Person
>> Director inherits Employee
>>
>> If I have an object Employee with a method getBoss() that returns an Employee (lazy loaded), I expect that sometimes it will be a director.
>> In iBATIS 2, testing (employee.getBoss() instanceof Director) will always be false. This problem is due to the fact that iBATIS does not know the real class of the boss property and creates a Proxy of Employee.
>> In iBATIS 3, testing (employee.getBoss() instanceof Director) will be true if the employee's boss is a Director. To know the real type, the statement must be executed.
>>
>> Christian
>>
>>
>> -----Original Message-----
>> From: Carlos Pita [mailto:carlosjosepita@gmail.com]
>> Sent: Wednesday, December 16, 2009 11:45 AM
>> To: user-java@ibatis.apache.org
>> Subject: Lazy loading differences between ibatis 2 and 3
>>
>> Hi all,
>>
>> I've the following sqlmap for ibatis 2. Suppose ibatis has its lazy-loading feature enabled and I obtain a user U by means of findUserById. Then I call U.getEmail() and findMemberById is not executed. That's fine, one wouldn't expect the associated member to be loaded until there is a real need for it. Of course, if then I call
>> U.getMember().getDescription() findMemberById does execute its select, in due time. That said, for ibatis 3 the same example executes findMemberById as soon as U.getEmail() is invoked, loading the member before time. That's not surprising if one inspects the code of ResultObjectProxy (relevant parts copied below). Is this intended to work the way it does or is it a bug?
>>
>> <sqlMap namespace="User">
>>
>>        <resultMap id="userMap" class="User">
>>        <result property="email" column="email"/>
>>        <result property="member" column="member_id" select="findMemberById"/>
>>        </resultMap>
>>
>>        <resultMap id="memberMap" class="Member">
>>        <result property="description" column="description"/>
>>        </resultMap>
>>
>>        <select id="findUserById" resultMap="userMap">
>>                select * from qpoint_user where id = #id#
>>        </select>
>>
>>        <select id="findMemberById" resultMap="memberMap">
>>                select * from cpp_member where member_id = #id#
>>        </select>
>>
>> </sqlMap>
>>
>>
>> public class ResultObjectProxy {
>>
>>   public Object invoke(Object o, Method method, Object[] args) throws Throwable {
>>      try {
>>        if (!Object.class.equals(method.getDeclaringClass()) &&
>> PropertyNamer.isGetter(method.getName())) {
>>            lazyLoader.loadAll(); <-- this loads all asociations for every getter invoked on this proxy
>>        }
>>        return method.invoke(target, args);
>>      } catch (Throwable t) {
>>        throw ExceptionUtil.unwrapThrowable(t);
>>      }
>>    }
>> }
>>
>> Regards
>> --
>> Bardamu
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
>> For additional commands, e-mail: user-java-help@ibatis.apache.org
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
>> For additional commands, e-mail: user-java-help@ibatis.apache.org
>>
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
> For additional commands, e-mail: user-java-help@ibatis.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
For additional commands, e-mail: user-java-help@ibatis.apache.org


RE: Lazy loading differences between ibatis 2 and 3

Posted by Poitras Christian <Ch...@ircm.qc.ca>.
Having a proxy that always extends Employee (never Director) would delay the lazy load. But doing this would cause this method to always return false:
public boolean askARase() {
  if (this.getBoss() instanceof Director) {
    return true;
  } else {
    return false;
  }
}

The proxy can only extend a single class, so when the boss proxy is created it must be of the right class. To be of the right class, the select must be executed before boss property is accessed in any way (including instanceof test). To be sure boss property is of the right type, it must be loaded as soon as any method on Employee is called.

I supposed an optimization that can be added to iBATIS is to check if the property is loaded by a select. If so, check it the select's resultMap contains a discriminator tag. If so load it before any method is called. If not, create a proxy and load the real object only when one of it's method is called.

If you program such a patch, I'm sure it will be appreciated.

Christian

-----Original Message-----
From: Carlos Pita [mailto:carlosjosepita@gmail.com] 
Sent: Wednesday, December 16, 2009 2:00 PM
To: user-java@ibatis.apache.org
Subject: Re: Lazy loading differences between ibatis 2 and 3

But as the proxy is a subclass of Employee, this.getBoss() will get intercepted by the proxy method handler which will load the boss immediately before hasMoney() is invoked on it. So I see no need to load it at the point of askARase() invocation.

Regards
--
Carlos


On Wed, Dec 16, 2009 at 4:45 PM, Poitras Christian <Ch...@ircm.qc.ca> wrote:
> Hi Bardamu,
>
> I think it was not clear enough due to the lack of Proxy explanation.
> If I have an employee and I call getBoss() on it, it has to load the boss property. But what if I call a method like this in employee?
> public boolean askARase() {
>  if (this.getBoss().hasMoney()) {
>    return true;
>  } else {
>    return false;
>  }
> }
>
> Then, I hope the boss property is loaded before hasMoney() is called on it.
> The boss property itself is a proxy that can be defined as <E extends Employee>, but what is E? Since iBATIS does not know for sure, I has to call the select to get the right type for boss as soon as any method on Employee is called.
>
> Christian
>
>
> -----Original Message-----
> From: Carlos Pita [mailto:carlosjosepita@gmail.com]
> Sent: Wednesday, December 16, 2009 12:16 PM
> To: user-java@ibatis.apache.org
> Subject: Re: Lazy loading differences between ibatis 2 and 3
>
> Hi Christian,
>
> I understand your point but I don't get its relation to my question at all. Continuing your example, I would ask why employee.getName() will prematurely load the boss. A priori, I would expect the proxy to be smarter and only trigger the loading of boss if getBoss() was effectively called.
>
> Regards
> --
> Bardamu
>
> On Wed, Dec 16, 2009 at 3:09 PM, Poitras Christian <Ch...@ircm.qc.ca> wrote:
>> Hi,
>>
>> The major problem that was present in iBATIS 2 was that lazy loaded class where not always of the right type.
>> For exemple, if I have multiple subclasses of a class.
>> Person
>> Employee inherits Person
>> Director inherits Employee
>>
>> If I have an object Employee with a method getBoss() that returns an Employee (lazy loaded), I expect that sometimes it will be a director.
>> In iBATIS 2, testing (employee.getBoss() instanceof Director) will always be false. This problem is due to the fact that iBATIS does not know the real class of the boss property and creates a Proxy of Employee.
>> In iBATIS 3, testing (employee.getBoss() instanceof Director) will be true if the employee's boss is a Director. To know the real type, the statement must be executed.
>>
>> Christian
>>
>>
>> -----Original Message-----
>> From: Carlos Pita [mailto:carlosjosepita@gmail.com]
>> Sent: Wednesday, December 16, 2009 11:45 AM
>> To: user-java@ibatis.apache.org
>> Subject: Lazy loading differences between ibatis 2 and 3
>>
>> Hi all,
>>
>> I've the following sqlmap for ibatis 2. Suppose ibatis has its 
>> lazy-loading feature enabled and I obtain a user U by means of 
>> findUserById. Then I call U.getEmail() and findMemberById is not 
>> executed. That's fine, one wouldn't expect the associated member to 
>> be loaded until there is a real need for it. Of course, if then I 
>> call
>> U.getMember().getDescription() findMemberById does execute its select, in due time. That said, for ibatis 3 the same example executes findMemberById as soon as U.getEmail() is invoked, loading the member before time. That's not surprising if one inspects the code of ResultObjectProxy (relevant parts copied below). Is this intended to work the way it does or is it a bug?
>>
>> <sqlMap namespace="User">
>>
>>        <resultMap id="userMap" class="User">
>>        <result property="email" column="email"/>
>>        <result property="member" column="member_id"
>> select="findMemberById"/>
>>        </resultMap>
>>
>>        <resultMap id="memberMap" class="Member">
>>        <result property="description" column="description"/>
>>        </resultMap>
>>
>>        <select id="findUserById" resultMap="userMap">
>>                select * from qpoint_user where id = #id#
>>        </select>
>>
>>        <select id="findMemberById" resultMap="memberMap">
>>                select * from cpp_member where member_id = #id#
>>        </select>
>>
>> </sqlMap>
>>
>>
>> public class ResultObjectProxy {
>>
>>   public Object invoke(Object o, Method method, Object[] args) throws 
>> Throwable {
>>      try {
>>        if (!Object.class.equals(method.getDeclaringClass()) &&
>> PropertyNamer.isGetter(method.getName())) {
>>            lazyLoader.loadAll(); <-- this loads all asociations for 
>> every getter invoked on this proxy
>>        }
>>        return method.invoke(target, args);
>>      } catch (Throwable t) {
>>        throw ExceptionUtil.unwrapThrowable(t);
>>      }
>>    }
>> }
>>
>> Regards
>> --
>> Bardamu
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
>> For additional commands, e-mail: user-java-help@ibatis.apache.org
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
>> For additional commands, e-mail: user-java-help@ibatis.apache.org
>>
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
> For additional commands, e-mail: user-java-help@ibatis.apache.org
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
> For additional commands, e-mail: user-java-help@ibatis.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
For additional commands, e-mail: user-java-help@ibatis.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
For additional commands, e-mail: user-java-help@ibatis.apache.org


Re: Lazy loading differences between ibatis 2 and 3

Posted by Carlos Pita <ca...@gmail.com>.
But as the proxy is a subclass of Employee, this.getBoss() will get
intercepted by the proxy method handler which will load the boss
immediately before hasMoney() is invoked on it. So I see no need to
load it at the point of askARase() invocation.

Regards
--
Carlos


On Wed, Dec 16, 2009 at 4:45 PM, Poitras Christian
<Ch...@ircm.qc.ca> wrote:
> Hi Bardamu,
>
> I think it was not clear enough due to the lack of Proxy explanation.
> If I have an employee and I call getBoss() on it, it has to load the boss property. But what if I call a method like this in employee?
> public boolean askARase() {
>  if (this.getBoss().hasMoney()) {
>    return true;
>  } else {
>    return false;
>  }
> }
>
> Then, I hope the boss property is loaded before hasMoney() is called on it.
> The boss property itself is a proxy that can be defined as <E extends Employee>, but what is E? Since iBATIS does not know for sure, I has to call the select to get the right type for boss as soon as any method on Employee is called.
>
> Christian
>
>
> -----Original Message-----
> From: Carlos Pita [mailto:carlosjosepita@gmail.com]
> Sent: Wednesday, December 16, 2009 12:16 PM
> To: user-java@ibatis.apache.org
> Subject: Re: Lazy loading differences between ibatis 2 and 3
>
> Hi Christian,
>
> I understand your point but I don't get its relation to my question at all. Continuing your example, I would ask why employee.getName() will prematurely load the boss. A priori, I would expect the proxy to be smarter and only trigger the loading of boss if getBoss() was effectively called.
>
> Regards
> --
> Bardamu
>
> On Wed, Dec 16, 2009 at 3:09 PM, Poitras Christian <Ch...@ircm.qc.ca> wrote:
>> Hi,
>>
>> The major problem that was present in iBATIS 2 was that lazy loaded class where not always of the right type.
>> For exemple, if I have multiple subclasses of a class.
>> Person
>> Employee inherits Person
>> Director inherits Employee
>>
>> If I have an object Employee with a method getBoss() that returns an Employee (lazy loaded), I expect that sometimes it will be a director.
>> In iBATIS 2, testing (employee.getBoss() instanceof Director) will always be false. This problem is due to the fact that iBATIS does not know the real class of the boss property and creates a Proxy of Employee.
>> In iBATIS 3, testing (employee.getBoss() instanceof Director) will be true if the employee's boss is a Director. To know the real type, the statement must be executed.
>>
>> Christian
>>
>>
>> -----Original Message-----
>> From: Carlos Pita [mailto:carlosjosepita@gmail.com]
>> Sent: Wednesday, December 16, 2009 11:45 AM
>> To: user-java@ibatis.apache.org
>> Subject: Lazy loading differences between ibatis 2 and 3
>>
>> Hi all,
>>
>> I've the following sqlmap for ibatis 2. Suppose ibatis has its
>> lazy-loading feature enabled and I obtain a user U by means of
>> findUserById. Then I call U.getEmail() and findMemberById is not
>> executed. That's fine, one wouldn't expect the associated member to be
>> loaded until there is a real need for it. Of course, if then I call
>> U.getMember().getDescription() findMemberById does execute its select, in due time. That said, for ibatis 3 the same example executes findMemberById as soon as U.getEmail() is invoked, loading the member before time. That's not surprising if one inspects the code of ResultObjectProxy (relevant parts copied below). Is this intended to work the way it does or is it a bug?
>>
>> <sqlMap namespace="User">
>>
>>        <resultMap id="userMap" class="User">
>>        <result property="email" column="email"/>
>>        <result property="member" column="member_id"
>> select="findMemberById"/>
>>        </resultMap>
>>
>>        <resultMap id="memberMap" class="Member">
>>        <result property="description" column="description"/>
>>        </resultMap>
>>
>>        <select id="findUserById" resultMap="userMap">
>>                select * from qpoint_user where id = #id#
>>        </select>
>>
>>        <select id="findMemberById" resultMap="memberMap">
>>                select * from cpp_member where member_id = #id#
>>        </select>
>>
>> </sqlMap>
>>
>>
>> public class ResultObjectProxy {
>>
>>   public Object invoke(Object o, Method method, Object[] args) throws
>> Throwable {
>>      try {
>>        if (!Object.class.equals(method.getDeclaringClass()) &&
>> PropertyNamer.isGetter(method.getName())) {
>>            lazyLoader.loadAll(); <-- this loads all asociations for
>> every getter invoked on this proxy
>>        }
>>        return method.invoke(target, args);
>>      } catch (Throwable t) {
>>        throw ExceptionUtil.unwrapThrowable(t);
>>      }
>>    }
>> }
>>
>> Regards
>> --
>> Bardamu
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
>> For additional commands, e-mail: user-java-help@ibatis.apache.org
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
>> For additional commands, e-mail: user-java-help@ibatis.apache.org
>>
>>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
> For additional commands, e-mail: user-java-help@ibatis.apache.org
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
> For additional commands, e-mail: user-java-help@ibatis.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
For additional commands, e-mail: user-java-help@ibatis.apache.org


RE: Lazy loading differences between ibatis 2 and 3

Posted by Poitras Christian <Ch...@ircm.qc.ca>.
Hi Bardamu,

I think it was not clear enough due to the lack of Proxy explanation.
If I have an employee and I call getBoss() on it, it has to load the boss property. But what if I call a method like this in employee?
public boolean askARase() {
  if (this.getBoss().hasMoney()) {
    return true;
  } else {
    return false;
  }
}

Then, I hope the boss property is loaded before hasMoney() is called on it.
The boss property itself is a proxy that can be defined as <E extends Employee>, but what is E? Since iBATIS does not know for sure, I has to call the select to get the right type for boss as soon as any method on Employee is called.

Christian


-----Original Message-----
From: Carlos Pita [mailto:carlosjosepita@gmail.com] 
Sent: Wednesday, December 16, 2009 12:16 PM
To: user-java@ibatis.apache.org
Subject: Re: Lazy loading differences between ibatis 2 and 3

Hi Christian,

I understand your point but I don't get its relation to my question at all. Continuing your example, I would ask why employee.getName() will prematurely load the boss. A priori, I would expect the proxy to be smarter and only trigger the loading of boss if getBoss() was effectively called.

Regards
--
Bardamu

On Wed, Dec 16, 2009 at 3:09 PM, Poitras Christian <Ch...@ircm.qc.ca> wrote:
> Hi,
>
> The major problem that was present in iBATIS 2 was that lazy loaded class where not always of the right type.
> For exemple, if I have multiple subclasses of a class.
> Person
> Employee inherits Person
> Director inherits Employee
>
> If I have an object Employee with a method getBoss() that returns an Employee (lazy loaded), I expect that sometimes it will be a director.
> In iBATIS 2, testing (employee.getBoss() instanceof Director) will always be false. This problem is due to the fact that iBATIS does not know the real class of the boss property and creates a Proxy of Employee.
> In iBATIS 3, testing (employee.getBoss() instanceof Director) will be true if the employee's boss is a Director. To know the real type, the statement must be executed.
>
> Christian
>
>
> -----Original Message-----
> From: Carlos Pita [mailto:carlosjosepita@gmail.com]
> Sent: Wednesday, December 16, 2009 11:45 AM
> To: user-java@ibatis.apache.org
> Subject: Lazy loading differences between ibatis 2 and 3
>
> Hi all,
>
> I've the following sqlmap for ibatis 2. Suppose ibatis has its 
> lazy-loading feature enabled and I obtain a user U by means of 
> findUserById. Then I call U.getEmail() and findMemberById is not 
> executed. That's fine, one wouldn't expect the associated member to be 
> loaded until there is a real need for it. Of course, if then I call
> U.getMember().getDescription() findMemberById does execute its select, in due time. That said, for ibatis 3 the same example executes findMemberById as soon as U.getEmail() is invoked, loading the member before time. That's not surprising if one inspects the code of ResultObjectProxy (relevant parts copied below). Is this intended to work the way it does or is it a bug?
>
> <sqlMap namespace="User">
>
>        <resultMap id="userMap" class="User">
>        <result property="email" column="email"/>
>        <result property="member" column="member_id" 
> select="findMemberById"/>
>        </resultMap>
>
>        <resultMap id="memberMap" class="Member">
>        <result property="description" column="description"/>
>        </resultMap>
>
>        <select id="findUserById" resultMap="userMap">
>                select * from qpoint_user where id = #id#
>        </select>
>
>        <select id="findMemberById" resultMap="memberMap">
>                select * from cpp_member where member_id = #id#
>        </select>
>
> </sqlMap>
>
>
> public class ResultObjectProxy {
>
>   public Object invoke(Object o, Method method, Object[] args) throws 
> Throwable {
>      try {
>        if (!Object.class.equals(method.getDeclaringClass()) &&
> PropertyNamer.isGetter(method.getName())) {
>            lazyLoader.loadAll(); <-- this loads all asociations for 
> every getter invoked on this proxy
>        }
>        return method.invoke(target, args);
>      } catch (Throwable t) {
>        throw ExceptionUtil.unwrapThrowable(t);
>      }
>    }
> }
>
> Regards
> --
> Bardamu
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
> For additional commands, e-mail: user-java-help@ibatis.apache.org
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
> For additional commands, e-mail: user-java-help@ibatis.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
For additional commands, e-mail: user-java-help@ibatis.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
For additional commands, e-mail: user-java-help@ibatis.apache.org


Re: Lazy loading differences between ibatis 2 and 3

Posted by Carlos Pita <ca...@gmail.com>.
Hi Christian,

I understand your point but I don't get its relation to my question at
all. Continuing your example, I would ask why employee.getName() will
prematurely load the boss. A priori, I would expect the proxy to be
smarter and only trigger the loading of boss if getBoss() was
effectively called.

Regards
--
Bardamu

On Wed, Dec 16, 2009 at 3:09 PM, Poitras Christian
<Ch...@ircm.qc.ca> wrote:
> Hi,
>
> The major problem that was present in iBATIS 2 was that lazy loaded class where not always of the right type.
> For exemple, if I have multiple subclasses of a class.
> Person
> Employee inherits Person
> Director inherits Employee
>
> If I have an object Employee with a method getBoss() that returns an Employee (lazy loaded), I expect that sometimes it will be a director.
> In iBATIS 2, testing (employee.getBoss() instanceof Director) will always be false. This problem is due to the fact that iBATIS does not know the real class of the boss property and creates a Proxy of Employee.
> In iBATIS 3, testing (employee.getBoss() instanceof Director) will be true if the employee's boss is a Director. To know the real type, the statement must be executed.
>
> Christian
>
>
> -----Original Message-----
> From: Carlos Pita [mailto:carlosjosepita@gmail.com]
> Sent: Wednesday, December 16, 2009 11:45 AM
> To: user-java@ibatis.apache.org
> Subject: Lazy loading differences between ibatis 2 and 3
>
> Hi all,
>
> I've the following sqlmap for ibatis 2. Suppose ibatis has its lazy-loading feature enabled and I obtain a user U by means of findUserById. Then I call U.getEmail() and findMemberById is not executed. That's fine, one wouldn't expect the associated member to be loaded until there is a real need for it. Of course, if then I call
> U.getMember().getDescription() findMemberById does execute its select, in due time. That said, for ibatis 3 the same example executes findMemberById as soon as U.getEmail() is invoked, loading the member before time. That's not surprising if one inspects the code of ResultObjectProxy (relevant parts copied below). Is this intended to work the way it does or is it a bug?
>
> <sqlMap namespace="User">
>
>        <resultMap id="userMap" class="User">
>        <result property="email" column="email"/>
>        <result property="member" column="member_id" select="findMemberById"/>
>        </resultMap>
>
>        <resultMap id="memberMap" class="Member">
>        <result property="description" column="description"/>
>        </resultMap>
>
>        <select id="findUserById" resultMap="userMap">
>                select * from qpoint_user where id = #id#
>        </select>
>
>        <select id="findMemberById" resultMap="memberMap">
>                select * from cpp_member where member_id = #id#
>        </select>
>
> </sqlMap>
>
>
> public class ResultObjectProxy {
>
>   public Object invoke(Object o, Method method, Object[] args) throws Throwable {
>      try {
>        if (!Object.class.equals(method.getDeclaringClass()) &&
> PropertyNamer.isGetter(method.getName())) {
>            lazyLoader.loadAll(); <-- this loads all asociations for every getter invoked on this proxy
>        }
>        return method.invoke(target, args);
>      } catch (Throwable t) {
>        throw ExceptionUtil.unwrapThrowable(t);
>      }
>    }
> }
>
> Regards
> --
> Bardamu
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
> For additional commands, e-mail: user-java-help@ibatis.apache.org
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
> For additional commands, e-mail: user-java-help@ibatis.apache.org
>
>

---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
For additional commands, e-mail: user-java-help@ibatis.apache.org


RE: Lazy loading differences between ibatis 2 and 3

Posted by Poitras Christian <Ch...@ircm.qc.ca>.
Hi,

The major problem that was present in iBATIS 2 was that lazy loaded class where not always of the right type.
For exemple, if I have multiple subclasses of a class.
Person
Employee inherits Person
Director inherits Employee

If I have an object Employee with a method getBoss() that returns an Employee (lazy loaded), I expect that sometimes it will be a director.
In iBATIS 2, testing (employee.getBoss() instanceof Director) will always be false. This problem is due to the fact that iBATIS does not know the real class of the boss property and creates a Proxy of Employee.
In iBATIS 3, testing (employee.getBoss() instanceof Director) will be true if the employee's boss is a Director. To know the real type, the statement must be executed.

Christian


-----Original Message-----
From: Carlos Pita [mailto:carlosjosepita@gmail.com] 
Sent: Wednesday, December 16, 2009 11:45 AM
To: user-java@ibatis.apache.org
Subject: Lazy loading differences between ibatis 2 and 3

Hi all,

I've the following sqlmap for ibatis 2. Suppose ibatis has its lazy-loading feature enabled and I obtain a user U by means of findUserById. Then I call U.getEmail() and findMemberById is not executed. That's fine, one wouldn't expect the associated member to be loaded until there is a real need for it. Of course, if then I call
U.getMember().getDescription() findMemberById does execute its select, in due time. That said, for ibatis 3 the same example executes findMemberById as soon as U.getEmail() is invoked, loading the member before time. That's not surprising if one inspects the code of ResultObjectProxy (relevant parts copied below). Is this intended to work the way it does or is it a bug?

<sqlMap namespace="User">

	<resultMap id="userMap" class="User">
        <result property="email" column="email"/>
        <result property="member" column="member_id" select="findMemberById"/>
	</resultMap>

	<resultMap id="memberMap" class="Member">
        <result property="description" column="description"/>
	</resultMap>

	<select id="findUserById" resultMap="userMap">
		select * from qpoint_user where id = #id#
	</select>

	<select id="findMemberById" resultMap="memberMap">
		select * from cpp_member where member_id = #id#
	</select>

</sqlMap>


public class ResultObjectProxy {

   public Object invoke(Object o, Method method, Object[] args) throws Throwable {
      try {
        if (!Object.class.equals(method.getDeclaringClass()) &&
PropertyNamer.isGetter(method.getName())) {
            lazyLoader.loadAll(); <-- this loads all asociations for every getter invoked on this proxy
        }
        return method.invoke(target, args);
      } catch (Throwable t) {
        throw ExceptionUtil.unwrapThrowable(t);
      }
    }
}

Regards
--
Bardamu

---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
For additional commands, e-mail: user-java-help@ibatis.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: user-java-unsubscribe@ibatis.apache.org
For additional commands, e-mail: user-java-help@ibatis.apache.org