ibatis-user-java mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Rick" <ricks_mailingli...@arc-mind.com>
Subject RE: One solution to self-join, new feature request.... RE: Employee self-join one to many relationship (iBatis)
Date Wed, 05 Jul 2006 18:05:30 GMT
I see. Hmmm. This is makes sense. 

 

 

My query is a "connect by" that gets all employees. All employees have a
boss, but not all employees have directReports. Will this still work? I
tried it as follows:

 

 

      <resultMap id="boss" class="qcom.cas.mysourcej.poc.model.Employee"
groupBy="emplid">

            <result property="emplid" column="emplid" />

            <result property="name" column="name" />

            <result property="bossId" column="bossId"/>

            <result property="employees"
resultMap="employee.employeeShort"/>

      </resultMap>

 

      <resultMap id="employeeShort"
class="qcom.cas.mysourcej.poc.model.Employee">

            <result property="emplid" column="emplid" />

            <result property="name" column="name" />

            <result property="bossId" column="bossId"/>

      </resultMap>

 

      <select id="getMyOrg" resultMap="employeeShort">

                  <![CDATA[

                        select

                              employee.emplid as emplid,

                              employee.name as name,

                              employee.N_SUPERVISOR as bossId,

                              boss.name as bossName

                        from

                              ps_employees employee

                        join ps_employees boss

                    on employee.N_SUPERVISOR = boss.emplid

                      start with

                        employee.emplid = #supervisorId#

                      connect by

                        employee.n_supervisor = prior employee.emplid

                        order by

                              level, name;

                 !]]>

      </select>

 

The query is a rollup query that builds a tree. For some reason, I can't get
the above query to run at all. It runs inside of SQL Navigator as follows:

 

 

                        select

                              employee.emplid as emplid,

                              employee.name as name,

                              employee.N_SUPERVISOR as bossId,

                              boss.name as bossName

                        from

                              ps_employees employee

                        join ps_employees boss

                    on employee.N_SUPERVISOR = boss.emplid

                      start with

                        employee.emplid = '12345'

                      connect by

                        employee.n_supervisor = prior employee.emplid

                        order by

                              level, name

 

 

Which results in:

 

12345               Tom Bridizzle                                        001
George Bush

30                     Brad Bojangles
12345               Tom Bridizzle

1                      David Efurdstein
12345               Tom Bridizzle

2                      Rick Hightower                                      1
David Efurdstein

3                      Scott Fauerbach                                   1
David Efurdstein

 

 

When I run it inside of iBatis I get:

 

(I tried with and without the ;)

org.springframework.jdbc.BadSqlGrammarException: SqlMapClient operation; bad
SQL grammar []; nested exception is
com.ibatis.common.jdbc.exception.NestedSQLException:   

--- The error occurred in qcom/cas/mysourcej/poc/dao/Employee.xml.  

--- The error occurred while applying a parameter map.  

--- Check the getMyOrg-InlineParameterMap.  

--- Check the statement (query failed).  

--- Cause: java.sql.SQLException: ORA-00911: invalid character

 

Caused by: java.sql.SQLException: ORA-00911: invalid character

 

Caused by: com.ibatis.common.jdbc.exception.NestedSQLException:   

--- The error occurred in qcom/cas/mysourcej/poc/dao/Employee.xml.  

--- The error occurred while applying a parameter map.  

--- Check the getMyOrg-InlineParameterMap.  

--- Check the statement (query failed).  

--- Cause: java.sql.SQLException: ORA-00911: invalid character

 

Caused by: java.sql.SQLException: ORA-00911: invalid character

 

            at
com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWith
Callback(GeneralStatement.java:185)

            at
com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryForL
ist(GeneralStatement.java:123)

            at
com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExec
utorDelegate.java:610)

            at
com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExec
utorDelegate.java:584)

            at
com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForList(SqlMapSessionIm
pl.java:101)

            at
org.springframework.orm.ibatis.SqlMapClientTemplate$3.doInSqlMapClient(SqlMa
pClientTemplate.java:228)

            at
org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemp
late.java:165)

            at
org.springframework.orm.ibatis.SqlMapClientTemplate.executeWithListResult(Sq
lMapClientTemplate.java:187)

            at
org.springframework.orm.ibatis.SqlMapClientTemplate.queryForList(SqlMapClien
tTemplate.java:226)

            at
qcom.cas.commons.dao.dataproducer.IBatisQueryDataProducer.executeNameParamsQ
uery(IBatisQueryDataProducer.java:75)

            at
qcom.cas.commons.dao.dataproducer.IBatisQueryDataProducer.list(IBatisQueryDa
taProducer.java:66)

            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:266)

            at
org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint
(ReflectiveMethodInvocation.java:181)

            at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(Reflect
iveMethodInvocation.java:148)

            at
org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(
DelegatingIntroductionInterceptor.java:124)

            at
org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(Del
egatingIntroductionInterceptor.java:112)

            at
qcom.cas.commons.faces.dataproducer.GetSelectItemsIntroduction.invoke(GetSel
ectItemsIntroduction.java:69)

            at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(Reflect
iveMethodInvocation.java:170)

            at
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopPro
xy.java:176)

            at $Proxy0.list(Unknown Source)

            at
qcom.cas.mysourcej.poc.backingbean.EmergencyContactBackingBean.myOrgClicked(
EmergencyContactBackingBean.java:93)

            at
qcom.cas.mysourcej.poc.backingbean.EmergencyContactBackingBeanTest.testShowM
yOrgTree(EmergencyContactBackingBeanTest.java:142)

            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 junit.framework.TestCase.runTest(TestCase.java:154)

            at junit.framework.TestCase.runBare(TestCase.java:127)

            at junit.framework.TestResult$1.protect(TestResult.java:106)

            at junit.framework.TestResult.runProtected(TestResult.java:124)

            at junit.framework.TestResult.run(TestResult.java:109)

            at junit.framework.TestCase.run(TestCase.java:118)

            at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRu
nner.java:478)

            at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.
java:344)

            at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner
.java:196)

Caused by: java.sql.SQLException: ORA-00911: invalid character

 

            at
oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:111)

            at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:330)

            at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:287)

            at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:742)

            at
oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:21
2)

            at
oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatem
ent.java:795)

            at
oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java
:1030)

            at
oracle.jdbc.driver.T4CPreparedStatement.executeMaybeDescribe(T4CPreparedStat
ement.java:835)

            at
oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java
:1123)

            at
oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedSta
tement.java:3284)

            at
oracle.jdbc.driver.OraclePreparedStatement.execute(OraclePreparedStatement.j
ava:3389)

            at
org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPrepar
edStatement.java:168)

            at
com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQuery(SqlExecutor.java
:180)

            at
com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.sqlExecuteQuery(
GeneralStatement.java:205)

            at
com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWith
Callback(GeneralStatement.java:173)

            ... 38 more

 

Caused by: 

java.sql.SQLException: ORA-00911: invalid character

 

            at
oracle.jdbc.driver.DatabaseError.throwSqlException(DatabaseError.java:111)

            at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:330)

            at oracle.jdbc.driver.T4CTTIoer.processError(T4CTTIoer.java:287)

            at oracle.jdbc.driver.T4C8Oall.receive(T4C8Oall.java:742)

            at
oracle.jdbc.driver.T4CPreparedStatement.doOall8(T4CPreparedStatement.java:21
2)

            at
oracle.jdbc.driver.T4CPreparedStatement.executeForDescribe(T4CPreparedStatem
ent.java:795)

            at
oracle.jdbc.driver.OracleStatement.executeMaybeDescribe(OracleStatement.java
:1030)

            at
oracle.jdbc.driver.T4CPreparedStatement.executeMaybeDescribe(T4CPreparedStat
ement.java:835)

            at
oracle.jdbc.driver.OracleStatement.doExecuteWithTimeout(OracleStatement.java
:1123)

            at
oracle.jdbc.driver.OraclePreparedStatement.executeInternal(OraclePreparedSta
tement.java:3284)

            at
oracle.jdbc.driver.OraclePreparedStatement.execute(OraclePreparedStatement.j
ava:3389)

            at
org.apache.commons.dbcp.DelegatingPreparedStatement.execute(DelegatingPrepar
edStatement.java:168)

            at
com.ibatis.sqlmap.engine.execution.SqlExecutor.executeQuery(SqlExecutor.java
:180)

            at
com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.sqlExecuteQuery(
GeneralStatement.java:205)

            at
com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryWith
Callback(GeneralStatement.java:173)

            at
com.ibatis.sqlmap.engine.mapping.statement.GeneralStatement.executeQueryForL
ist(GeneralStatement.java:123)

            at
com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExec
utorDelegate.java:610)

            at
com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate.queryForList(SqlMapExec
utorDelegate.java:584)

            at
com.ibatis.sqlmap.engine.impl.SqlMapSessionImpl.queryForList(SqlMapSessionIm
pl.java:101)

            at
org.springframework.orm.ibatis.SqlMapClientTemplate$3.doInSqlMapClient(SqlMa
pClientTemplate.java:228)

            at
org.springframework.orm.ibatis.SqlMapClientTemplate.execute(SqlMapClientTemp
late.java:165)

            at
org.springframework.orm.ibatis.SqlMapClientTemplate.executeWithListResult(Sq
lMapClientTemplate.java:187)

            at
org.springframework.orm.ibatis.SqlMapClientTemplate.queryForList(SqlMapClien
tTemplate.java:226)

            at
qcom.cas.commons.dao.dataproducer.IBatisQueryDataProducer.executeNameParamsQ
uery(IBatisQueryDataProducer.java:75)

            at
qcom.cas.commons.dao.dataproducer.IBatisQueryDataProducer.list(IBatisQueryDa
taProducer.java:66)

            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:266)

            at
org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint
(ReflectiveMethodInvocation.java:181)

            at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(Reflect
iveMethodInvocation.java:148)

            at
org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(
DelegatingIntroductionInterceptor.java:124)

            at
org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(Del
egatingIntroductionInterceptor.java:112)

            at
qcom.cas.commons.faces.dataproducer.GetSelectItemsIntroduction.invoke(GetSel
ectItemsIntroduction.java:69)

            at
org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(Reflect
iveMethodInvocation.java:170)

            at
org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopPro
xy.java:176)

            at $Proxy0.list(Unknown Source)

            at
qcom.cas.mysourcej.poc.backingbean.EmergencyContactBackingBean.myOrgClicked(
EmergencyContactBackingBean.java:93)

            at
qcom.cas.mysourcej.poc.backingbean.EmergencyContactBackingBeanTest.testShowM
yOrgTree(EmergencyContactBackingBeanTest.java:142)

            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 junit.framework.TestCase.runTest(TestCase.java:154)

            at junit.framework.TestCase.runBare(TestCase.java:127)

            at junit.framework.TestResult$1.protect(TestResult.java:106)

            at junit.framework.TestResult.runProtected(TestResult.java:124)

            at junit.framework.TestResult.run(TestResult.java:109)

            at junit.framework.TestCase.run(TestCase.java:118)

            at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRu
nner.java:478)

            at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.
java:344)

            at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner
.java:196)

 

 

  _____  

From: Jeff Butler [mailto:jeffgbutler@gmail.com] 
Sent: Wednesday, July 05, 2006 9:54 AM
To: user-java@ibatis.apache.org
Subject: Re: One solution to self-join, new feature request.... RE: Employee
self-join one to many relationship (iBatis)

 

Hi Rick,

 

A self join can be accomplished through groupBy and column renaming.  Here's
a simple example I just coded up for a test:

 

Table Definition:

 

create table employees(id int not null, bossId int, name varchar(50))

 

Class Definition:

 

public class Employee {

  private Integer id;

  private String name;

  private List employees;

  // getters/setters

}

 

 

iBATIS stuff:

<resultMap id="boss" class="test.Employee" groupBy="id">
  <result property="id" column="bossId" />
  <result property="name" column="bossName" /> 
  <result property="employees" resultMap="employee"/>
</resultMap>

<resultMap id="employee" class="test.Employee">
  <result property="id" column="employeeId" />
  <result property="name" column="employeeName" /> 
</resultMap>

<select id="selectEmployees" resultMap="boss">
  select a.id as employeedId, a.name as employeeName, b.id as bossId, b.name
as bossName
  from employees a join employees b
    on a.bossId = b.id
  where a.bossId is not null
</select>

This returns all the data in one pass, so no N+1 problem.

 

Jeff Butler


 

On 7/5/06, Rick <ricks_mailinglists@arc-mind.com> wrote: 

Someone sent me a solution to the self-join that I asked about earlier as
follows:

       <resultMap id="employee" class=" sample01.Employee">
               <result property="employeeId" column="employee_id"/>
               <result property="bossId" column="boss_id" nullValue="-1" 
select="getBoss"/>
               <result property="firstName" column="first_name"/>
               <result property="lastName" column="last_name"/> 
       </resultMap>
       <statement id="getEmployees" resultMap="employee">
               select * from Employee
       </statement>
       <statement id="getBoss" resultMap="employee"> 
               select * from Employee where employee_id=#value#
       </statement>


This is very helpful in understanding how iBatis works. I think I will stick
with the other approach b/c the code above would perform 1 query for each 
boss (N+1). The approach I used (with the helper method) only hits the db
once. It gets all the data it needs in one swipe and then builds the
hierarchy.


Again, my former approach gets all of the employees in the tree (using 
connect-by) and then constructs the hierarchy.


The above way is much cleaner in that it does not require custom Java code
to build the list. Its runtime performance would be problematic especially
since I am replacing code that does not have an N+1 issue (custom VB/ASP 
app).

I'd like to have something like this (as a new feature in iBatis):

       <resultMap id="employee" class="sample01.Employee">
               <result property="employeeId" column="employee_id"/> 
               <result property="boss" fk_property="bossId"
                   adder-method="addDirectReport" self-join="true"
                   pk_property="emplId"/> 
               <result property="firstName" column="first_name"/>
               <result property="bossId" column="n_supervisor"/>
               <result property="lastName" column="last_name"/> 
       </resultMap>
       <statement id="getEmployees" resultMap="employee">
               select * from Employee e
                   start with n_supervisor = #supervisorId# 
                   connect by n_supervisor = prior emplid
      </statement>


See the:

               <result property="boss" fk_property="bossId"
                   adder-method="addDirectReport" self-join="true" 
                   pk_property="emplId"/>

Basically the data for the hierarchy is already retrieved from the db. Why
hit it a second time?

Thoughts?


-----Original Message-----
From: Larry Meadors [mailto:lmeadors@apache.org]
Sent: Monday, July 03, 2006 3:54 PM
To: user-java@ibatis.apache.org
Subject: Re: Employee self-join one to many relationship (iBatis) 

Hmm, I generally don't build my object model that way, so my
experience with groupBy is sort of limited, sorry. ;-)

If you can't make groupBy work, I'd look at doing this with a
rowhandler. You'd get all the data in one hit to the database, and 
then step through the results building the object graph the way you
want it.

Larry


On 7/3/06, Rick <ricks_mailinglists@arc-mind.com> wrote: 
> Bingo!
>
> Yep. Employee has a directReports list which is a list of Employees.
>
>
>
> -----Original Message-----
> From: Larry Meadors [mailto: <mailto:lmeadors@apache.org>
lmeadors@apache.org]
> Sent: Monday, July 03, 2006 3:19 PM
> To: user-java@ibatis.apache.org
> Subject: Re: Employee self-join one to many relationship (iBatis) 
>
> Hey Rick, I am not 100% sure I understand what you are trying to do,
> but let me try to restate it and see..
>
> Do you want a list of employees, each one with another list of
> employees (direct reports), and a list of contacts on each one - both 
> the main employee list and the child employees?
>
> Larry
>
>
> On 7/3/06, Rick <ricks_mailinglists@arc-mind.com> wrote:
> >
> >
> >
> >
> > I just want to use iBatis in the cleanest way possible. I have a
> workaround
> > but wonder if iBatis support self-joined one to many relationships. 
> >
> >
> >
> > Let me explain..
> >
> >
> >
> >
> >
> > I have a query that returns employees.
> >
> >
> > 
> > Employees have Boss's who are Employees.
> >
> >
> >
> > Currently I have Employees have Contacts who have Phone Numbers.
> >
> >
> >
> > (Where Employee, Contact and Phone number are objects.) 
> >
> >
> >
> > I'd like to have Employees have Employees (directReports) and Employees
> have
> > Contacts who have Phone Numbers.
> >
> >
> > 
> > Does iBatis support a self join?
> >
> >
> >
> >
> >
> > Here is my current mapping and how I get around this lack of support (or
> is
> > this support lacking)... 
> >
> >
> >
> > , i.e.,
> >
> >
> >
> >       <resultMap id="employee"
> > class="qcom.cas.mysourcej.poc.model.Employee" 
> > groupBy="emplid">
> >
> >             <result property="emplid" column="emplid" />
> >
> >             <result property="name" column="name" /> 
> >
> >             <result property="contacts" resultMap="employee.contacts"/>
> >
> >             <result property="bossId" column="bossId"/> 
> >
> >       </resultMap>
> >
> >
> >
> >       <resultMap id="contacts"
> > class="qcom.cas.mysourcej.poc.model.Contact">
> >
> >             <result property="name" column="contact_name"/>
> >
> >             <result property="primaryContact" column="primary_contact" 
> >
> >
> >
typeHandler="qcom.cas.commons.ibatis.typehandler.StringBooleanTypeHandler"
> > />
> >
> >             <result property="relationship" column="relation"/> 
> >
> >             <result property="phoneNumber1.number" column="phone1"/>
> >
> >             <result property="phoneNumber2.number" column="phone2"/> 
> >
> >             <result property="phoneNumber3.number" column="phone3"/>
> >
> >             <result property="phoneNumber4.number" column="phone4"/> 
> >
> >             <result property="phoneNumber1.areaCode"
column="areaCode1"/>
> >
> >             <result property="phoneNumber2.areaCode" 
column="areaCode2"/>
> >
> >             <result property="phoneNumber3.areaCode"
column="areaCode3"/>
> >
> >             <result property=" phoneNumber4.areaCode"
column="areaCode4"/>
> >
> >       </resultMap>
> >
> >
> >
> >
> >
> >
> >
> >       <select 
> > id="getEmployeeEmergencyContactsUsingDirectSort"
> > resultMap="employee">
> >
> >
> >
> >
> >
> > If so, any pointers or references where I can learn to do this.. 
> >
> >
> >
> > Currently I have a method that turns the list of employees into a
> hierarchy
> > of Employees as follows:
> >
> >
> >
> >       /** 
> >
> >        * Turns a list of employees into a hierarchy of employees.
> >
> >        * @param employees
> >
> >        * @param removeChild
> >
> >        */ 
> >
> >       private void buildEmployeeObjectHierarchy(List
> > employees, boolean removeChild) {
> >
> >             Map employeeIDMap = new HashMap(employees.size());
> > 
> >
> >
> >             for (Iterator iter = employees.iterator(); iter.hasNext();)
{
> >
> >                   Employee employee = (Employee) iter.next();
> >
> >                   employeeIDMap.put(employee.getEmplid(), employee);
> >
> >             }
> >
> >
> >
> >             for (Iterator iter = employees.iterator (); iter.hasNext();)
{
> >
> >                   Employee employee = (Employee) iter.next();
> >
> >                   Employee boss = (Employee)
> > employeeIDMap.get(employee.getBossId ());
> >
> >                   if (boss != null) {
> >
> >                         boss.addEmployee(employee);
> >
> >                         iter.remove(); //If a boss is found, remove this

> > employee from the list.
> >
> >                   }
> >
> >             }
> >
> >       }
> >
> >
> >
> > The above is a bit expensive and I'd like to get it out of my code if 
> > possible. If not, no worries. I just want to use iBatis in the cleanest
> way
> > possible.
>
>
>



 


Mime
View raw message