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 Jerome Jacobsen <je...@gentootech.com> on 2004/12/10 16:03:16 UTC
Avoiding N+1 with complex HashMap properties.
Hello,
I'm using SQL Maps 2.08. I was hoping I could do the following
but I get a ProbeException. Should this be supported?
<resultMap id="get-customer-period-result"
class="java.util.HashMap">
<result property="customerNum"
column="CUSTOMER_NUMBER"
columnIndex="1"/>
<result property="category.id"
column="CATEGORY_ID"
columnIndex="2"/>
<result property="category.parentId"
column="PARENT_CATEGORY_ID"
columnIndex="3"/>
<result property="category.description"
column="CATEGORY_DESC"
columnIndex="4"/>
...
</resultMap>
<statement id="getCustomerPeriodSummary"
resultMap="get-customer-period-result">
SELECT CPS.CUSTOMER_NUMBER,
PC.CATEGORY_ID,
PC.PARENT_CATEGORY_ID,
PC.DESCRIPTION AS CATEGORY_DESC,
PC.SEQUENCE AS CATEGORY_SEQUENCE,
...
FROM CUSTOMER_PERIOD_SUMMARY CPS, PRODUCT_CATEGORY PC, SALES_PERIOD SP
WHERE CPS.CUSTOMER_NUMBER = #value#
AND CPS.CATEGORY_ID = PC.CATEGORY_ID
AND CPS.PERIOD_ID = SP.PERIOD_ID
ORDER BY CATEGORY_SEQUENCE
</statement>
I was hoping that sqlmaps would store the 'category.id',
'category.parentId', 'category.description' either in a nested
HashMap (key of 'category') or store the values in the top
level HashMap with those keys ('category.id', etc.)
However neither case appears to happen and I get the
exception below. I realize that I can map the complex
properties with separate selects but I want to avoid the
N+1 query problem. So I do the join instead.
com.ibatis.common.beans.ProbeException: There is no WRITEABLE property named
'id' in class 'java.lang.Object'
at com.ibatis.common.beans.ClassInfo.getSetter(ClassInfo.java:146)
at
com.ibatis.common.beans.ComplexBeanProbe.setProperty(ComplexBeanProbe.java:3
34)
at
com.ibatis.common.beans.ComplexBeanProbe.setObject(ComplexBeanProbe.java:231
)
at com.ibatis.common.beans.GenericProbe.setObject(GenericProbe.java:69)
at
com.ibatis.sqlmap.engine.exchange.ComplexDataExchange.setData(ComplexDataExc
hange.java:87)
at
com.ibatis.sqlmap.engine.mapping.result.BasicResultMap.setResultObjectValues
(BasicResultMap.java:231)
at
com.ibatis.sqlmap.engine.mapping.statement.RowHandlerCallback.handleResultOb
ject(RowHandlerCallback.java:63)
at
com.ibatis.sqlmap.engine.execution.SqlExecutor.handleResults(SqlExecutor.jav
a:350)
at
com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQuery(SqlExecutor.java
:179)
at
com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.sqlExecuteQuery(
GeneralStatement.java:200)
at
com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWith
Callback(GeneralStatement.java:168)
at
com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryForL
ist(GeneralStatement.java:118)
at
com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExec
utorDelegate.java:626)
at
com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExec
utorDelegate.java:598)
at
com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForList(SqlMapSessionIm
pl.java:107)
at
org.springframework.orm.ibatis.SqlMapClientTemplate$3.doInSqlMapClient(SqlMa
pClientTemplate.java:202)
at
org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemp
late.java:142)
at
org.springframework.orm.ibatis.SqlMapClientTemplate.executeWithListResult(Sq
lMapClientTemplate.java:164)
at
org.springframework.orm.ibatis.SqlMapClientTemplate.queryForList(SqlMapClien
tTemplate.java:200)
at
com.giv.dashboard.dao.db.ibatis.SqlMapSalesStatisticsDAO.getCategoryStatsFor
Customer(SqlMapSalesStatisticsDAO.java:28)
at
com.giv.dashboard.DashboardImpl.getCategorySummaries(DashboardImpl.java:42)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39
)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl
.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at
org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopU
tils.java:295)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint
(ReflectiveMethodInvocation.java:154)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(Reflect
iveMethodInvocation.java:121)
at
org.springframework.transaction.interceptor.TransactionInterceptor.invoke(Tr
ansactionInterceptor.java:56)
at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(Reflect
iveMethodInvocation.java:143)
at
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopPro
xy.java:174)
at $Proxy0.getCategorySummaries(Unknown Source)
at
com.giv.dashboard.web.spring.ViewCategoriesController.handleRequestInternal(
ViewCategoriesController.java:62)
at
org.springframework.web.servlet.mvc.AbstractController.handleRequest(Abstrac
tController.java:128)
at
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(Si
mpleControllerHandlerAdapter.java:44)
at
org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServle
t.java:532)
at
org.springframework.web.servlet.FrameworkServlet.serviceWrapper(FrameworkSer
vlet.java:366)
at
org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java
:317)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:740)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
at
com.evermind.server.http.ResourceFilterChain.doFilter(ResourceFilterChain.ja
va:65)
at oracle.security.jazn.oc4j.JAZNFilter.doFilter(Unknown Source)
at
com.evermind.server.http.ServletRequestDispatcher.invoke(ServletRequestDispa
tcher.java:604)
at
com.evermind.server.http.ServletRequestDispatcher.forwardInternal(ServletReq
uestDispatcher.java:317)
at
com.evermind.server.http.HttpRequestHandler.processRequest(HttpRequestHandle
r.java:790)
at
com.evermind.server.http.HttpRequestHandler.run(HttpRequestHandler.java:270)
at
com.evermind.server.http.HttpRequestHandler.run(HttpRequestHandler.java:112)
at
com.evermind.util.ReleasableResourcePooledExecutor$MyWorker.run(ReleasableRe
sourcePooledExecutor.java:192)
at java.lang.Thread.run(Thread.java:534)
RE: Avoiding N+1 with complex HashMap properties.
Posted by Jerome Jacobsen <je...@gentootech.com>.
Darn typo! Option 2 should say:
HashMap customer = customerDao.getCustomer(id);
HashMap address = customer.get("address");
out.println("customer state = " + address.get("state"));
customer.get("address") instead of customerDao.get("address")
We're getting the 'address' HashMap from the 'customer'
HashMap.
> -----Original Message-----
> From: Jerome Jacobsen [mailto:jerome.jacobsen@gentootech.com]
> Sent: Friday, December 10, 2004 12:49 PM
> To: ibatis-user-java@incubator.apache.org
> Subject: RE: Avoiding N+1 with complex HashMap properties.
>
>
> Just to be clear, here are examples of what I'm talking about.
>
> Option 1: Single hashmap with indexed property style keys.
>
> HashMap customer = customerDao.getCustomer(id);
> out.println("customer state = " + customer.get("address.state"));
>
> Option 2: Nested hashmaps.
>
> HashMap customer = customerDao.getCustomer(id);
> HashMap address = customerDao.get("address");
> out.println("customer state = " + address.get("state"));
>
>
> I have no preference as to which way is supported, as long as:
> - The exception doesn't occur.
> - I can access the properties using the 'indexed property'
> style in JSP.
>
> I'm not sure how JSTL/JSP would handle the nested HashMap versus
> handling the single HashMap.
>
> In JSP not sure if I can do this for both implementations
> above:
>
> Customer State = <c:out value="${customer.address.state}"/>
>
> If JSP/JSTL only supports one of these implementation options
> then that would be my preference for ibatis too.
>
> Regards,
>
> Jerome
>
> > -----Original Message-----
> > From: Clinton Begin [mailto:clinton.begin@gmail.com]
> > Sent: Friday, December 10, 2004 10:09 AM
> > To: jerome.jacobsen@gentootech.com
> > Cc: ibatis-user-java@incubator.apache.org
> > Subject: Re: Avoiding N+1 with complex HashMap properties.
> >
> >
> > Tough call. Some people want it stored as a single property (e.g.
> > imagine the key is a classname), and others want it stored nested.
> >
> > Currently, as you've discovered, it's not nested.
> >
> > I would suggest that if you have a complex object model, then you
> > should model it using JavaBeans. Maps are very loose, unpredictable
> > and limited.
> >
> > Cheers,
> > Clinton
> >
> >
> > On Fri, 10 Dec 2004 10:03:16 -0500, Jerome Jacobsen
> > <je...@gentootech.com> wrote:
> > > Hello,
> > >
> > > I'm using SQL Maps 2.08. I was hoping I could do the following
> > > but I get a ProbeException. Should this be supported?
> > >
> > > <resultMap id="get-customer-period-result"
> > > class="java.util.HashMap">
> > > <result property="customerNum"
> > > column="CUSTOMER_NUMBER"
> > > columnIndex="1"/>
> > > <result property="category.id"
> > > column="CATEGORY_ID"
> > > columnIndex="2"/>
> > > <result property="category.parentId"
> > > column="PARENT_CATEGORY_ID"
> > > columnIndex="3"/>
> > > <result property="category.description"
> > > column="CATEGORY_DESC"
> > > columnIndex="4"/>
> > > ...
> > > </resultMap>
> > >
> > > <statement id="getCustomerPeriodSummary"
> > > resultMap="get-customer-period-result">
> > > SELECT CPS.CUSTOMER_NUMBER,
> > > PC.CATEGORY_ID,
> > > PC.PARENT_CATEGORY_ID,
> > > PC.DESCRIPTION AS CATEGORY_DESC,
> > > PC.SEQUENCE AS CATEGORY_SEQUENCE,
> > > ...
> > > FROM CUSTOMER_PERIOD_SUMMARY CPS, PRODUCT_CATEGORY PC,
> > SALES_PERIOD SP
> > > WHERE CPS.CUSTOMER_NUMBER = #value#
> > > AND CPS.CATEGORY_ID = PC.CATEGORY_ID
> > > AND CPS.PERIOD_ID = SP.PERIOD_ID
> > > ORDER BY CATEGORY_SEQUENCE
> > > </statement>
> > >
> > > I was hoping that sqlmaps would store the 'category.id',
> > > 'category.parentId', 'category.description' either in a nested
> > > HashMap (key of 'category') or store the values in the top
> > > level HashMap with those keys ('category.id', etc.)
> > >
> > > However neither case appears to happen and I get the
> > > exception below. I realize that I can map the complex
> > > properties with separate selects but I want to avoid the
> > > N+1 query problem. So I do the join instead.
> > >
> > > com.ibatis.common.beans.ProbeException: There is no WRITEABLE
> > property named
> > > 'id' in class 'java.lang.Object'
> > > at
> > com.ibatis.common.beans.ClassInfo.getSetter(ClassInfo.java:146)
> > > at
> > >
> > com.ibatis.common.beans.ComplexBeanProbe.setProperty(ComplexBeanPr
> > obe.java:3
> > > 34)
> > > at
> > >
> > com.ibatis.common.beans.ComplexBeanProbe.setObject(ComplexBeanProb
> > e.java:231
> > > )
> > > at
> > com.ibatis.common.beans.GenericProbe.setObject(GenericProbe.java:69)
> > > at
> > >
> > com.ibatis.sqlmap.engine.exchange.ComplexDataExchange.setData(Comp
> > lexDataExc
> > > hange.java:87)
> > > at
> > >
> > com.ibatis.sqlmap.engine.mapping.result.BasicResultMap.setResultOb
> > jectValues
> > > (BasicResultMap.java:231)
> > > at
> > >
> > com.ibatis.sqlmap.engine.mapping.statement.RowHandlerCallback.hand
> > leResultOb
> > > ject(RowHandlerCallback.java:63)
> > > at
> > >
> > com.ibatis.sqlmap.engine.execution.SqlExecutor.handleResults(SqlEx
> > ecutor.jav
> > > a:350)
> > > at
> > >
> > com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQuery(SqlExe
> > cutor.java
> > > :179)
> > > at
> > >
> > com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.sqlExe
> > cuteQuery(
> > > GeneralStatement.java:200)
> > > at
> > >
> > com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.execut
> > eQueryWith
> > > Callback(GeneralStatement.java:168)
> > > at
> > >
> > com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.execut
> > eQueryForL
> > > ist(GeneralStatement.java:118)
> > > at
> > >
> > com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(
> > SqlMapExec
> > > utorDelegate.java:626)
> > > at
> > >
> > com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(
> > SqlMapExec
> > > utorDelegate.java:598)
> > > at
> > >
> > com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForList(SqlMa
> > pSessionIm
> > > pl.java:107)
> > > at
> > >
> > org.springframework.orm.ibatis.SqlMapClientTemplate$3.doInSqlMapCl
> > ient(SqlMa
> > > pClientTemplate.java:202)
> > > at
> > >
> > org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMap
> > ClientTemp
> > > late.java:142)
> > > at
> > >
> > org.springframework.orm.ibatis.SqlMapClientTemplate.executeWithLis
> > tResult(Sq
> > > lMapClientTemplate.java:164)
> > > at
> > >
> > org.springframework.orm.ibatis.SqlMapClientTemplate.queryForList(S
> > qlMapClien
> > > tTemplate.java:200)
> > > at
> > >
> > com.giv.dashboard.dao.db.ibatis.SqlMapSalesStatisticsDAO.getCatego
> > ryStatsFor
> > > Customer(SqlMapSalesStatisticsDAO.java:28)
> > > at
> > >
> > com.giv.dashboard.DashboardImpl.getCategorySummaries(DashboardImpl
> > .java:42)
> > > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> > > at
> > >
> > sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorIm
> > pl.java:39
> > > )
> > > at
> > >
> > sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAc
> > cessorImpl
> > > .java:25)
> > > at java.lang.reflect.Method.invoke(Method.java:324)
> > > at
> > >
> > org.springframework.aop.support.AopUtils.invokeJoinpointUsingRefle
> > ction(AopU
> > > tils.java:295)
> > > at
> > >
> > org.springframework.aop.framework.ReflectiveMethodInvocation.invok
> > eJoinpoint
> > > (ReflectiveMethodInvocation.java:154)
> > > at
> > >
> > org.springframework.aop.framework.ReflectiveMethodInvocation.proce
> > ed(Reflect
> > > iveMethodInvocation.java:121)
> > > at
> > >
> > org.springframework.transaction.interceptor.TransactionInterceptor
> > .invoke(Tr
> > > ansactionInterceptor.java:56)
> > > at
> > >
> > org.springframework.aop.framework.ReflectiveMethodInvocation.proce
> > ed(Reflect
> > > iveMethodInvocation.java:143)
> > > at
> > >
> > org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDyn
> > amicAopPro
> > > xy.java:174)
> > > at $Proxy0.getCategorySummaries(Unknown Source)
> > > at
> > >
> > com.giv.dashboard.web.spring.ViewCategoriesController.handleReques
> > tInternal(
> > > ViewCategoriesController.java:62)
> > > at
> > >
> > org.springframework.web.servlet.mvc.AbstractController.handleReque
> > st(Abstrac
> > > tController.java:128)
> > > at
> > >
> > org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
> > .handle(Si
> > > mpleControllerHandlerAdapter.java:44)
> > > at
> > >
> > org.springframework.web.servlet.DispatcherServlet.doService(Dispat
> > cherServle
> > > t.java:532)
> > > at
> > >
> > org.springframework.web.servlet.FrameworkServlet.serviceWrapper(Fr
> > ameworkSer
> > > vlet.java:366)
> > > at
> > >
> > org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkSe
> > rvlet.java
> > > :317)
> > > at
> javax.servlet.http.HttpServlet.service(HttpServlet.java:740)
> > > at
> javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
> > > at
> > >
> > com.evermind.server.http.ResourceFilterChain.doFilter(ResourceFilt
> > erChain.ja
> > > va:65)
> > > at
> oracle.security.jazn.oc4j.JAZNFilter.doFilter(Unknown Source)
> > > at
> > >
> > com.evermind.server.http.ServletRequestDispatcher.invoke(ServletRe
> > questDispa
> > > tcher.java:604)
> > > at
> > >
> > com.evermind.server.http.ServletRequestDispatcher.forwardInternal(
> > ServletReq
> > > uestDispatcher.java:317)
> > > at
> > >
> > com.evermind.server.http.HttpRequestHandler.processRequest(HttpReq
> > uestHandle
> > > r.java:790)
> > > at
> > >
> > com.evermind.server.http.HttpRequestHandler.run(HttpRequestHandler
> > .java:270)
> > > at
> > >
> > com.evermind.server.http.HttpRequestHandler.run(HttpRequestHandler
> > .java:112)
> > > at
> > >
> > com.evermind.util.ReleasableResourcePooledExecutor$MyWorker.run(Re
> > leasableRe
> > > sourcePooledExecutor.java:192)
> > > at java.lang.Thread.run(Thread.java:534)
> > >
> > >
> >
RE: Avoiding N+1 with complex HashMap properties.
Posted by Jerome Jacobsen <je...@gentootech.com>.
Just to be clear, here are examples of what I'm talking about.
Option 1: Single hashmap with indexed property style keys.
HashMap customer = customerDao.getCustomer(id);
out.println("customer state = " + customer.get("address.state"));
Option 2: Nested hashmaps.
HashMap customer = customerDao.getCustomer(id);
HashMap address = customerDao.get("address");
out.println("customer state = " + address.get("state"));
I have no preference as to which way is supported, as long as:
- The exception doesn't occur.
- I can access the properties using the 'indexed property'
style in JSP.
I'm not sure how JSTL/JSP would handle the nested HashMap versus
handling the single HashMap.
In JSP not sure if I can do this for both implementations
above:
Customer State = <c:out value="${customer.address.state}"/>
If JSP/JSTL only supports one of these implementation options
then that would be my preference for ibatis too.
Regards,
Jerome
> -----Original Message-----
> From: Clinton Begin [mailto:clinton.begin@gmail.com]
> Sent: Friday, December 10, 2004 10:09 AM
> To: jerome.jacobsen@gentootech.com
> Cc: ibatis-user-java@incubator.apache.org
> Subject: Re: Avoiding N+1 with complex HashMap properties.
>
>
> Tough call. Some people want it stored as a single property (e.g.
> imagine the key is a classname), and others want it stored nested.
>
> Currently, as you've discovered, it's not nested.
>
> I would suggest that if you have a complex object model, then you
> should model it using JavaBeans. Maps are very loose, unpredictable
> and limited.
>
> Cheers,
> Clinton
>
>
> On Fri, 10 Dec 2004 10:03:16 -0500, Jerome Jacobsen
> <je...@gentootech.com> wrote:
> > Hello,
> >
> > I'm using SQL Maps 2.08. I was hoping I could do the following
> > but I get a ProbeException. Should this be supported?
> >
> > <resultMap id="get-customer-period-result"
> > class="java.util.HashMap">
> > <result property="customerNum"
> > column="CUSTOMER_NUMBER"
> > columnIndex="1"/>
> > <result property="category.id"
> > column="CATEGORY_ID"
> > columnIndex="2"/>
> > <result property="category.parentId"
> > column="PARENT_CATEGORY_ID"
> > columnIndex="3"/>
> > <result property="category.description"
> > column="CATEGORY_DESC"
> > columnIndex="4"/>
> > ...
> > </resultMap>
> >
> > <statement id="getCustomerPeriodSummary"
> > resultMap="get-customer-period-result">
> > SELECT CPS.CUSTOMER_NUMBER,
> > PC.CATEGORY_ID,
> > PC.PARENT_CATEGORY_ID,
> > PC.DESCRIPTION AS CATEGORY_DESC,
> > PC.SEQUENCE AS CATEGORY_SEQUENCE,
> > ...
> > FROM CUSTOMER_PERIOD_SUMMARY CPS, PRODUCT_CATEGORY PC,
> SALES_PERIOD SP
> > WHERE CPS.CUSTOMER_NUMBER = #value#
> > AND CPS.CATEGORY_ID = PC.CATEGORY_ID
> > AND CPS.PERIOD_ID = SP.PERIOD_ID
> > ORDER BY CATEGORY_SEQUENCE
> > </statement>
> >
> > I was hoping that sqlmaps would store the 'category.id',
> > 'category.parentId', 'category.description' either in a nested
> > HashMap (key of 'category') or store the values in the top
> > level HashMap with those keys ('category.id', etc.)
> >
> > However neither case appears to happen and I get the
> > exception below. I realize that I can map the complex
> > properties with separate selects but I want to avoid the
> > N+1 query problem. So I do the join instead.
> >
> > com.ibatis.common.beans.ProbeException: There is no WRITEABLE
> property named
> > 'id' in class 'java.lang.Object'
> > at
> com.ibatis.common.beans.ClassInfo.getSetter(ClassInfo.java:146)
> > at
> >
> com.ibatis.common.beans.ComplexBeanProbe.setProperty(ComplexBeanPr
> obe.java:3
> > 34)
> > at
> >
> com.ibatis.common.beans.ComplexBeanProbe.setObject(ComplexBeanProb
> e.java:231
> > )
> > at
> com.ibatis.common.beans.GenericProbe.setObject(GenericProbe.java:69)
> > at
> >
> com.ibatis.sqlmap.engine.exchange.ComplexDataExchange.setData(Comp
> lexDataExc
> > hange.java:87)
> > at
> >
> com.ibatis.sqlmap.engine.mapping.result.BasicResultMap.setResultOb
> jectValues
> > (BasicResultMap.java:231)
> > at
> >
> com.ibatis.sqlmap.engine.mapping.statement.RowHandlerCallback.hand
> leResultOb
> > ject(RowHandlerCallback.java:63)
> > at
> >
> com.ibatis.sqlmap.engine.execution.SqlExecutor.handleResults(SqlEx
> ecutor.jav
> > a:350)
> > at
> >
> com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQuery(SqlExe
> cutor.java
> > :179)
> > at
> >
> com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.sqlExe
> cuteQuery(
> > GeneralStatement.java:200)
> > at
> >
> com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.execut
> eQueryWith
> > Callback(GeneralStatement.java:168)
> > at
> >
> com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.execut
> eQueryForL
> > ist(GeneralStatement.java:118)
> > at
> >
> com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(
> SqlMapExec
> > utorDelegate.java:626)
> > at
> >
> com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(
> SqlMapExec
> > utorDelegate.java:598)
> > at
> >
> com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForList(SqlMa
> pSessionIm
> > pl.java:107)
> > at
> >
> org.springframework.orm.ibatis.SqlMapClientTemplate$3.doInSqlMapCl
> ient(SqlMa
> > pClientTemplate.java:202)
> > at
> >
> org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMap
> ClientTemp
> > late.java:142)
> > at
> >
> org.springframework.orm.ibatis.SqlMapClientTemplate.executeWithLis
> tResult(Sq
> > lMapClientTemplate.java:164)
> > at
> >
> org.springframework.orm.ibatis.SqlMapClientTemplate.queryForList(S
> qlMapClien
> > tTemplate.java:200)
> > at
> >
> com.giv.dashboard.dao.db.ibatis.SqlMapSalesStatisticsDAO.getCatego
> ryStatsFor
> > Customer(SqlMapSalesStatisticsDAO.java:28)
> > at
> >
> com.giv.dashboard.DashboardImpl.getCategorySummaries(DashboardImpl
> .java:42)
> > at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> > at
> >
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorIm
> pl.java:39
> > )
> > at
> >
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAc
> cessorImpl
> > .java:25)
> > at java.lang.reflect.Method.invoke(Method.java:324)
> > at
> >
> org.springframework.aop.support.AopUtils.invokeJoinpointUsingRefle
> ction(AopU
> > tils.java:295)
> > at
> >
> org.springframework.aop.framework.ReflectiveMethodInvocation.invok
> eJoinpoint
> > (ReflectiveMethodInvocation.java:154)
> > at
> >
> org.springframework.aop.framework.ReflectiveMethodInvocation.proce
> ed(Reflect
> > iveMethodInvocation.java:121)
> > at
> >
> org.springframework.transaction.interceptor.TransactionInterceptor
> .invoke(Tr
> > ansactionInterceptor.java:56)
> > at
> >
> org.springframework.aop.framework.ReflectiveMethodInvocation.proce
> ed(Reflect
> > iveMethodInvocation.java:143)
> > at
> >
> org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDyn
> amicAopPro
> > xy.java:174)
> > at $Proxy0.getCategorySummaries(Unknown Source)
> > at
> >
> com.giv.dashboard.web.spring.ViewCategoriesController.handleReques
> tInternal(
> > ViewCategoriesController.java:62)
> > at
> >
> org.springframework.web.servlet.mvc.AbstractController.handleReque
> st(Abstrac
> > tController.java:128)
> > at
> >
> org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter
> .handle(Si
> > mpleControllerHandlerAdapter.java:44)
> > at
> >
> org.springframework.web.servlet.DispatcherServlet.doService(Dispat
> cherServle
> > t.java:532)
> > at
> >
> org.springframework.web.servlet.FrameworkServlet.serviceWrapper(Fr
> ameworkSer
> > vlet.java:366)
> > at
> >
> org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkSe
> rvlet.java
> > :317)
> > at javax.servlet.http.HttpServlet.service(HttpServlet.java:740)
> > at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
> > at
> >
> com.evermind.server.http.ResourceFilterChain.doFilter(ResourceFilt
> erChain.ja
> > va:65)
> > at oracle.security.jazn.oc4j.JAZNFilter.doFilter(Unknown Source)
> > at
> >
> com.evermind.server.http.ServletRequestDispatcher.invoke(ServletRe
> questDispa
> > tcher.java:604)
> > at
> >
> com.evermind.server.http.ServletRequestDispatcher.forwardInternal(
> ServletReq
> > uestDispatcher.java:317)
> > at
> >
> com.evermind.server.http.HttpRequestHandler.processRequest(HttpReq
> uestHandle
> > r.java:790)
> > at
> >
> com.evermind.server.http.HttpRequestHandler.run(HttpRequestHandler
> .java:270)
> > at
> >
> com.evermind.server.http.HttpRequestHandler.run(HttpRequestHandler
> .java:112)
> > at
> >
> com.evermind.util.ReleasableResourcePooledExecutor$MyWorker.run(Re
> leasableRe
> > sourcePooledExecutor.java:192)
> > at java.lang.Thread.run(Thread.java:534)
> >
> >
>
Re: Avoiding N+1 with complex HashMap properties.
Posted by Clinton Begin <cl...@gmail.com>.
Tough call. Some people want it stored as a single property (e.g.
imagine the key is a classname), and others want it stored nested.
Currently, as you've discovered, it's not nested.
I would suggest that if you have a complex object model, then you
should model it using JavaBeans. Maps are very loose, unpredictable
and limited.
Cheers,
Clinton
On Fri, 10 Dec 2004 10:03:16 -0500, Jerome Jacobsen
<je...@gentootech.com> wrote:
> Hello,
>
> I'm using SQL Maps 2.08. I was hoping I could do the following
> but I get a ProbeException. Should this be supported?
>
> <resultMap id="get-customer-period-result"
> class="java.util.HashMap">
> <result property="customerNum"
> column="CUSTOMER_NUMBER"
> columnIndex="1"/>
> <result property="category.id"
> column="CATEGORY_ID"
> columnIndex="2"/>
> <result property="category.parentId"
> column="PARENT_CATEGORY_ID"
> columnIndex="3"/>
> <result property="category.description"
> column="CATEGORY_DESC"
> columnIndex="4"/>
> ...
> </resultMap>
>
> <statement id="getCustomerPeriodSummary"
> resultMap="get-customer-period-result">
> SELECT CPS.CUSTOMER_NUMBER,
> PC.CATEGORY_ID,
> PC.PARENT_CATEGORY_ID,
> PC.DESCRIPTION AS CATEGORY_DESC,
> PC.SEQUENCE AS CATEGORY_SEQUENCE,
> ...
> FROM CUSTOMER_PERIOD_SUMMARY CPS, PRODUCT_CATEGORY PC, SALES_PERIOD SP
> WHERE CPS.CUSTOMER_NUMBER = #value#
> AND CPS.CATEGORY_ID = PC.CATEGORY_ID
> AND CPS.PERIOD_ID = SP.PERIOD_ID
> ORDER BY CATEGORY_SEQUENCE
> </statement>
>
> I was hoping that sqlmaps would store the 'category.id',
> 'category.parentId', 'category.description' either in a nested
> HashMap (key of 'category') or store the values in the top
> level HashMap with those keys ('category.id', etc.)
>
> However neither case appears to happen and I get the
> exception below. I realize that I can map the complex
> properties with separate selects but I want to avoid the
> N+1 query problem. So I do the join instead.
>
> com.ibatis.common.beans.ProbeException: There is no WRITEABLE property named
> 'id' in class 'java.lang.Object'
> at com.ibatis.common.beans.ClassInfo.getSetter(ClassInfo.java:146)
> at
> com.ibatis.common.beans.ComplexBeanProbe.setProperty(ComplexBeanProbe.java:3
> 34)
> at
> com.ibatis.common.beans.ComplexBeanProbe.setObject(ComplexBeanProbe.java:231
> )
> at com.ibatis.common.beans.GenericProbe.setObject(GenericProbe.java:69)
> at
> com.ibatis.sqlmap.engine.exchange.ComplexDataExchange.setData(ComplexDataExc
> hange.java:87)
> at
> com.ibatis.sqlmap.engine.mapping.result.BasicResultMap.setResultObjectValues
> (BasicResultMap.java:231)
> at
> com.ibatis.sqlmap.engine.mapping.statement.RowHandlerCallback.handleResultOb
> ject(RowHandlerCallback.java:63)
> at
> com.ibatis.sqlmap.engine.execution.SqlExecutor.handleResults(SqlExecutor.jav
> a:350)
> at
> com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQuery(SqlExecutor.java
> :179)
> at
> com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.sqlExecuteQuery(
> GeneralStatement.java:200)
> at
> com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWith
> Callback(GeneralStatement.java:168)
> at
> com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryForL
> ist(GeneralStatement.java:118)
> at
> com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExec
> utorDelegate.java:626)
> at
> com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExec
> utorDelegate.java:598)
> at
> com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForList(SqlMapSessionIm
> pl.java:107)
> at
> org.springframework.orm.ibatis.SqlMapClientTemplate$3.doInSqlMapClient(SqlMa
> pClientTemplate.java:202)
> at
> org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemp
> late.java:142)
> at
> org.springframework.orm.ibatis.SqlMapClientTemplate.executeWithListResult(Sq
> lMapClientTemplate.java:164)
> at
> org.springframework.orm.ibatis.SqlMapClientTemplate.queryForList(SqlMapClien
> tTemplate.java:200)
> at
> com.giv.dashboard.dao.db.ibatis.SqlMapSalesStatisticsDAO.getCategoryStatsFor
> Customer(SqlMapSalesStatisticsDAO.java:28)
> at
> com.giv.dashboard.DashboardImpl.getCategorySummaries(DashboardImpl.java:42)
> at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
> at
> sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39
> )
> at
> sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl
> .java:25)
> at java.lang.reflect.Method.invoke(Method.java:324)
> at
> org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopU
> tils.java:295)
> at
> org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint
> (ReflectiveMethodInvocation.java:154)
> at
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(Reflect
> iveMethodInvocation.java:121)
> at
> org.springframework.transaction.interceptor.TransactionInterceptor.invoke(Tr
> ansactionInterceptor.java:56)
> at
> org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(Reflect
> iveMethodInvocation.java:143)
> at
> org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopPro
> xy.java:174)
> at $Proxy0.getCategorySummaries(Unknown Source)
> at
> com.giv.dashboard.web.spring.ViewCategoriesController.handleRequestInternal(
> ViewCategoriesController.java:62)
> at
> org.springframework.web.servlet.mvc.AbstractController.handleRequest(Abstrac
> tController.java:128)
> at
> org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(Si
> mpleControllerHandlerAdapter.java:44)
> at
> org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServle
> t.java:532)
> at
> org.springframework.web.servlet.FrameworkServlet.serviceWrapper(FrameworkSer
> vlet.java:366)
> at
> org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java
> :317)
> at javax.servlet.http.HttpServlet.service(HttpServlet.java:740)
> at javax.servlet.http.HttpServlet.service(HttpServlet.java:853)
> at
> com.evermind.server.http.ResourceFilterChain.doFilter(ResourceFilterChain.ja
> va:65)
> at oracle.security.jazn.oc4j.JAZNFilter.doFilter(Unknown Source)
> at
> com.evermind.server.http.ServletRequestDispatcher.invoke(ServletRequestDispa
> tcher.java:604)
> at
> com.evermind.server.http.ServletRequestDispatcher.forwardInternal(ServletReq
> uestDispatcher.java:317)
> at
> com.evermind.server.http.HttpRequestHandler.processRequest(HttpRequestHandle
> r.java:790)
> at
> com.evermind.server.http.HttpRequestHandler.run(HttpRequestHandler.java:270)
> at
> com.evermind.server.http.HttpRequestHandler.run(HttpRequestHandler.java:112)
> at
> com.evermind.util.ReleasableResourcePooledExecutor$MyWorker.run(ReleasableRe
> sourcePooledExecutor.java:192)
> at java.lang.Thread.run(Thread.java:534)
>
>