selectByExample is ambiguous in Mapped Statements collection

classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

selectByExample is ambiguous in Mapped Statements collection

Riccardo Cossu
Hello,
I'm trying to write a "generic" dao for different tables which may
share a few columns. I defined a hierarchy of mappers which reflects
this table structure (that is I have a BaseMapper which defines a
"selectByExample" query, which is overridden by specific mappers).
All mappers have their own different namespace and this is confermed
because debugging the session configuration I see that
"selectByExample" is bound in different namespaces.

I'm trying to execute this statement:

U mapper = session.getMapper(namespace);
List<T> list = mapper.selectByExample(example);

where <T> is declared as <T extends BaseBean>, U as <U extends
BaseBeanMapper<T>>,  namespace is a Class<U> and example is an
instance of <T>.

I would thik that session.getMapper would return me a Mapper where
selectByExample is bound to the specific namespace, but this isn't the
case, I get this exception:

java.lang.IllegalArgumentException: selectByExample is ambiguous in
Mapped Statements collection (try using the full name including the
namespace, or rename one of the entries)
at org.apache.ibatis.session.Configuration
$StrictMap.get(Configuration.java:466)
        at
org.apache.ibatis.session.Configuration.getMappedStatement(Configuration.java:
349)
        at
org.apache.ibatis.binding.MapperMethod.setupCommandType(MapperMethod.java:
137)
        at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:
46)
        at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:34)
        at $Proxy6.selectByExample(Unknown Source)

I'm using mybatis 3.0.2 on java 1.5, with java configuration (not
XML), using the "companion XML mapping" pattern described in the user
guide; the mapping files are like this, where like I said the
namespace part is different and unique for every mapper:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="avvocati24.StatoMapper">
        <resultMap id="detailStato" type="Stato">
                <result property="id" column="idStato" />
        </resultMap>
        <select id="selectByExample" parameterType="Stato"
                resultMap="detailStato">
                select * from Stato
                <where>
                        <if test="id != null">
                                idStato = #{id}
                        </if>
                </where>
        </select>
        <select id="selectById" parameterType="int" resultMap="detailStato">
                select *
                from Stato
                WHERE idStato = #{id}
        </select>
</mapper>

What is the correct way to address my needs?

Thanks for any help,
Riccardo
Reply | Threaded
Open this post in threaded view
|

Re: selectByExample is ambiguous in Mapped Statements collection

Riccardo Cossu
In the end I found that there was no need in my project for such a
thing, I think it's mostly a hibernate/jpa attitude that drives that
way (one class per table).

But if anyone knows the answer I would be glad to hear :-)

Thanks,
Riccardo

On 16 Set, 14:34, Riccardo <[hidden email]> wrote:

> Hello,
> I'm trying to write a "generic" dao for different tables which may
> share a few columns. I defined a hierarchy of mappers which reflects
> this table structure (that is I have a BaseMapper which defines a
> "selectByExample" query, which is overridden by specific mappers).
> All mappers have their own different namespace and this is confermed
> because debugging the session configuration I see that
> "selectByExample" is bound in different namespaces.
>
> I'm trying to execute this statement:
>
> U mapper = session.getMapper(namespace);
> List<T> list = mapper.selectByExample(example);
>
> where <T> is declared as <T extends BaseBean>, U as <U extends
> BaseBeanMapper<T>>,  namespace is a Class<U> and example is an
> instance of <T>.
>
> I would thik that session.getMapper would return me a Mapper where
> selectByExample is bound to the specific namespace, but this isn't the
> case, I get this exception:
>
> java.lang.IllegalArgumentException: selectByExample is ambiguous in
> Mapped Statements collection (try using the full name including the
> namespace, or rename one of the entries)
> at org.apache.ibatis.session.Configuration
> $StrictMap.get(Configuration.java:466)
>         at
> org.apache.ibatis.session.Configuration.getMappedStatement(Configuration.ja va:
> 349)
>         at
> org.apache.ibatis.binding.MapperMethod.setupCommandType(MapperMethod.java:
> 137)
>         at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:
> 46)
>         at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:34)
>         at $Proxy6.selectByExample(Unknown Source)
>
> I'm using mybatis 3.0.2 on java 1.5, with java configuration (not
> XML), using the "companion XML mapping" pattern described in the user
> guide; the mapping files are like this, where like I said the
> namespace part is different and unique for every mapper:
>
> <?xml version="1.0" encoding="UTF-8" ?>
> <!DOCTYPE mapper
> PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
> "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
> <mapper namespace="avvocati24.StatoMapper">
>         <resultMap id="detailStato" type="Stato">
>                 <result property="id" column="idStato" />
>         </resultMap>
>         <select id="selectByExample" parameterType="Stato"
>                 resultMap="detailStato">
>                 select * from Stato
>                 <where>
>                         <if test="id != null">
>                                 idStato = #{id}
>                         </if>
>                 </where>
>         </select>
>         <select id="selectById" parameterType="int" resultMap="detailStato">
>                 select *
>                 from Stato
>                 WHERE idStato = #{id}
>         </select>
> </mapper>
>
> What is the correct way to address my needs?
>
> Thanks for any help,
> Riccardo
Reply | Threaded
Open this post in threaded view
|

Re: selectByExample is ambiguous in Mapped Statements collection

Clinton Begin
Administrator
I read the original post and sounds like something that should work... but if I recall, when you register a mapper, it gets registered under 2 names:  The fully qualified name, and the short name.  So if you have two methods with the same name, then they'll have to be fully qualified when you call them.  The hard thing for me to understand was how you were calling it. 

Maybe if you get 10 minutes, throw a simple unit test together and file it in the issue tracker.

Clinton

On Fri, Sep 17, 2010 at 6:57 AM, Riccardo <[hidden email]> wrote:
In the end I found that there was no need in my project for such a
thing, I think it's mostly a hibernate/jpa attitude that drives that
way (one class per table).

But if anyone knows the answer I would be glad to hear :-)

Thanks,
Riccardo

On 16 Set, 14:34, Riccardo <[hidden email]> wrote:
> Hello,
> I'm trying to write a "generic" dao for different tables which may
> share a few columns. I defined a hierarchy of mappers which reflects
> this table structure (that is I have a BaseMapper which defines a
> "selectByExample" query, which is overridden by specific mappers).
> All mappers have their own different namespace and this is confermed
> because debugging the session configuration I see that
> "selectByExample" is bound in different namespaces.
>
> I'm trying to execute this statement:
>
> U mapper = session.getMapper(namespace);
> List<T> list = mapper.selectByExample(example);
>
> where <T> is declared as <T extends BaseBean>, U as <U extends
> BaseBeanMapper<T>>,  namespace is a Class<U> and example is an
> instance of <T>.
>
> I would thik that session.getMapper would return me a Mapper where
> selectByExample is bound to the specific namespace, but this isn't the
> case, I get this exception:
>
> java.lang.IllegalArgumentException: selectByExample is ambiguous in
> Mapped Statements collection (try using the full name including the
> namespace, or rename one of the entries)
> at org.apache.ibatis.session.Configuration
> $StrictMap.get(Configuration.java:466)
>         at
> org.apache.ibatis.session.Configuration.getMappedStatement(Configuration.ja va:
> 349)
>         at
> org.apache.ibatis.binding.MapperMethod.setupCommandType(MapperMethod.java:
> 137)
>         at org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:
> 46)
>         at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:34)
>         at $Proxy6.selectByExample(Unknown Source)
>
> I'm using mybatis 3.0.2 on java 1.5, with java configuration (not
> XML), using the "companion XML mapping" pattern described in the user
> guide; the mapping files are like this, where like I said the
> namespace part is different and unique for every mapper:
>
> <?xml version="1.0" encoding="UTF-8" ?>
> <!DOCTYPE mapper
> PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
> "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
> <mapper namespace="avvocati24.StatoMapper">
>         <resultMap id="detailStato" type="Stato">
>                 <result property="id" column="idStato" />
>         </resultMap>
>         <select id="selectByExample" parameterType="Stato"
>                 resultMap="detailStato">
>                 select * from Stato
>                 <where>
>                         <if test="id != null">
>                                 idStato = #{id}
>                         </if>
>                 </where>
>         </select>
>         <select id="selectById" parameterType="int" resultMap="detailStato">
>                 select *
>                 from Stato
>                 WHERE idStato = #{id}
>         </select>
> </mapper>
>
> What is the correct way to address my needs?
>
> Thanks for any help,
> Riccardo

Tim
Reply | Threaded
Open this post in threaded view
|

Re: selectByExample is ambiguous in Mapped Statements collection

Tim
I have something that sounds extremely similar to you.
I have a method defined as:

    @NotNull
    public <T, M extends StaticDataDao<T>> List<T> selectAll(@NotNull
Class<M> aMapperType) {
        final SqlSession mySession = theSessionFactory.openSession();
        try {
            final M myMapper = mySession.getMapper(aMapperType);
            return myMapper.selectAll();
        } finally {
            mySession.close();
        }
    }

The trick here is that each dao MUST implement the selectAll in their
respective mapper xmls (or in their annotations) IFF (if and only if
for those that weren't comp sci majors) you have more than one mapper
already defining that method. Unless you are using it specifically
from the namespaces defined with the selectAlls

So to recap.
If I had 3 mappers A, B, C
And A had
     <select id="selectAll" resultMap="SomeMap">
        <include refid="findAllSQL"/> <!-- don't be too concerned with
the syntax here -->
    </select>
In its namespace then it will work for ALL combinations of:
A.selectAll
B.selectAll
C.selectAll
selectAll

If I had A AND B mappers defined with that then it would be:
A.selectAll  - works
B.selectAll  - works
C.selectAll  - FAILS
selectAll - FAILS

I had a semi related blog post on this subject
http://blog.chengin.com/?p=32

On Fri, Sep 17, 2010 at 10:49 AM, Clinton Begin <[hidden email]> wrote:

> I read the original post and sounds like something that should work... but
> if I recall, when you register a mapper, it gets registered under 2 names:
>  The fully qualified name, and the short name.  So if you have two methods
> with the same name, then they'll have to be fully qualified when you call
> them.  The hard thing for me to understand was how you were calling it.
> Maybe if you get 10 minutes, throw a simple unit test together and file it
> in the issue tracker.
> Clinton
>
> On Fri, Sep 17, 2010 at 6:57 AM, Riccardo <[hidden email]> wrote:
>>
>> In the end I found that there was no need in my project for such a
>> thing, I think it's mostly a hibernate/jpa attitude that drives that
>> way (one class per table).
>>
>> But if anyone knows the answer I would be glad to hear :-)
>>
>> Thanks,
>> Riccardo
>>
>> On 16 Set, 14:34, Riccardo <[hidden email]> wrote:
>> > Hello,
>> > I'm trying to write a "generic" dao for different tables which may
>> > share a few columns. I defined a hierarchy of mappers which reflects
>> > this table structure (that is I have a BaseMapper which defines a
>> > "selectByExample" query, which is overridden by specific mappers).
>> > All mappers have their own different namespace and this is confermed
>> > because debugging the session configuration I see that
>> > "selectByExample" is bound in different namespaces.
>> >
>> > I'm trying to execute this statement:
>> >
>> > U mapper = session.getMapper(namespace);
>> > List<T> list = mapper.selectByExample(example);
>> >
>> > where <T> is declared as <T extends BaseBean>, U as <U extends
>> > BaseBeanMapper<T>>,  namespace is a Class<U> and example is an
>> > instance of <T>.
>> >
>> > I would thik that session.getMapper would return me a Mapper where
>> > selectByExample is bound to the specific namespace, but this isn't the
>> > case, I get this exception:
>> >
>> > java.lang.IllegalArgumentException: selectByExample is ambiguous in
>> > Mapped Statements collection (try using the full name including the
>> > namespace, or rename one of the entries)
>> > at org.apache.ibatis.session.Configuration
>> > $StrictMap.get(Configuration.java:466)
>> >         at
>> >
>> > org.apache.ibatis.session.Configuration.getMappedStatement(Configuration.ja
>> > va:
>> > 349)
>> >         at
>> >
>> > org.apache.ibatis.binding.MapperMethod.setupCommandType(MapperMethod.java:
>> > 137)
>> >         at
>> > org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:
>> > 46)
>> >         at
>> > org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:34)
>> >         at $Proxy6.selectByExample(Unknown Source)
>> >
>> > I'm using mybatis 3.0.2 on java 1.5, with java configuration (not
>> > XML), using the "companion XML mapping" pattern described in the user
>> > guide; the mapping files are like this, where like I said the
>> > namespace part is different and unique for every mapper:
>> >
>> > <?xml version="1.0" encoding="UTF-8" ?>
>> > <!DOCTYPE mapper
>> > PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
>> > "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
>> > <mapper namespace="avvocati24.StatoMapper">
>> >         <resultMap id="detailStato" type="Stato">
>> >                 <result property="id" column="idStato" />
>> >         </resultMap>
>> >         <select id="selectByExample" parameterType="Stato"
>> >                 resultMap="detailStato">
>> >                 select * from Stato
>> >                 <where>
>> >                         <if test="id != null">
>> >                                 idStato = #{id}
>> >                         </if>
>> >                 </where>
>> >         </select>
>> >         <select id="selectById" parameterType="int"
>> > resultMap="detailStato">
>> >                 select *
>> >                 from Stato
>> >                 WHERE idStato = #{id}
>> >         </select>
>> > </mapper>
>> >
>> > What is the correct way to address my needs?
>> >
>> > Thanks for any help,
>> > Riccardo
>
Reply | Threaded
Open this post in threaded view
|

Re: selectByExample is ambiguous in Mapped Statements collection

Riccardo Cossu
Hello Clinton and Tim,
I have uploaded a sample project to test the problem:
http://code.google.com/p/mybatis/issues/detail?id=112

I think the problem may be more a generics fault, than a specific
ibatis one, as proposed by Tim; don't know if ibatis could do anything
about it.
Or maybe I got the model wrong and someone can give me some hints on
how to get it right.

Thanks to you both anyway,
Riccardo

On 17 Set, 18:11, Tim <[hidden email]> wrote:

> I have something that sounds extremely similar to you.
> I have a method defined as:
>
>     @NotNull
>     public <T, M extends StaticDataDao<T>> List<T> selectAll(@NotNull
> Class<M> aMapperType) {
>         final SqlSession mySession = theSessionFactory.openSession();
>         try {
>             final M myMapper = mySession.getMapper(aMapperType);
>             return myMapper.selectAll();
>         } finally {
>             mySession.close();
>         }
>     }
>
> The trick here is that each dao MUST implement the selectAll in their
> respective mapper xmls (or in their annotations) IFF (if and only if
> for those that weren't comp sci majors) you have more than one mapper
> already defining that method. Unless you are using it specifically
> from the namespaces defined with the selectAlls
>
> So to recap.
> If I had 3 mappers A, B, C
> And A had
>      <select id="selectAll" resultMap="SomeMap">
>         <include refid="findAllSQL"/> <!-- don't be too concerned with
> the syntax here -->
>     </select>
> In its namespace then it will work for ALL combinations of:
> A.selectAll
> B.selectAll
> C.selectAll
> selectAll
>
> If I had A AND B mappers defined with that then it would be:
> A.selectAll  - works
> B.selectAll  - works
> C.selectAll  - FAILS
> selectAll - FAILS
>
> I had a semi related blog post on this subjecthttp://blog.chengin.com/?p=32
>
>
>
> On Fri, Sep 17, 2010 at 10:49 AM, Clinton Begin <[hidden email]> wrote:
> > I read the original post and sounds like something that should work... but
> > if I recall, when you register a mapper, it gets registered under 2 names:
> >  The fully qualified name, and the short name.  So if you have two methods
> > with the same name, then they'll have to be fully qualified when you call
> > them.  The hard thing for me to understand was how you were calling it.
> > Maybe if you get 10 minutes, throw a simple unit test together and file it
> > in the issue tracker.
> > Clinton
>
> > On Fri, Sep 17, 2010 at 6:57 AM, Riccardo <[hidden email]> wrote:
>
> >> In the end I found that there was no need in my project for such a
> >> thing, I think it's mostly a hibernate/jpa attitude that drives that
> >> way (one class per table).
>
> >> But if anyone knows the answer I would be glad to hear :-)
>
> >> Thanks,
> >> Riccardo
>
> >> On 16 Set, 14:34, Riccardo <[hidden email]> wrote:
> >> > Hello,
> >> > I'm trying to write a "generic" dao for different tables which may
> >> > share a few columns. I defined a hierarchy of mappers which reflects
> >> > this table structure (that is I have a BaseMapper which defines a
> >> > "selectByExample" query, which is overridden by specific mappers).
> >> > All mappers have their own different namespace and this is confermed
> >> > because debugging the session configuration I see that
> >> > "selectByExample" is bound in different namespaces.
>
> >> > I'm trying to execute this statement:
>
> >> > U mapper = session.getMapper(namespace);
> >> > List<T> list = mapper.selectByExample(example);
>
> >> > where <T> is declared as <T extends BaseBean>, U as <U extends
> >> > BaseBeanMapper<T>>,  namespace is a Class<U> and example is an
> >> > instance of <T>.
>
> >> > I would thik that session.getMapper would return me a Mapper where
> >> > selectByExample is bound to the specific namespace, but this isn't the
> >> > case, I get this exception:
>
> >> > java.lang.IllegalArgumentException: selectByExample is ambiguous in
> >> > Mapped Statements collection (try using the full name including the
> >> > namespace, or rename one of the entries)
> >> > at org.apache.ibatis.session.Configuration
> >> > $StrictMap.get(Configuration.java:466)
> >> >         at
>
> >> > org.apache.ibatis.session.Configuration.getMappedStatement(Configuration.ja
> >> > va:
> >> > 349)
> >> >         at
>
> >> > org.apache.ibatis.binding.MapperMethod.setupCommandType(MapperMethod.java:
> >> > 137)
> >> >         at
> >> > org.apache.ibatis.binding.MapperMethod.<init>(MapperMethod.java:
> >> > 46)
> >> >         at
> >> > org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:34)
> >> >         at $Proxy6.selectByExample(Unknown Source)
>
> >> > I'm using mybatis 3.0.2 on java 1.5, with java configuration (not
> >> > XML), using the "companion XML mapping" pattern described in the user
> >> > guide; the mapping files are like this, where like I said the
> >> > namespace part is different and unique for every mapper:
>
> >> > <?xml version="1.0" encoding="UTF-8" ?>
> >> > <!DOCTYPE mapper
> >> > PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
> >> > "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
> >> > <mapper namespace="avvocati24.StatoMapper">
> >> >         <resultMap id="detailStato" type="Stato">
> >> >                 <result property="id" column="idStato" />
> >> >         </resultMap>
> >> >         <select id="selectByExample" parameterType="Stato"
> >> >                 resultMap="detailStato">
> >> >                 select * from Stato
> >> >                 <where>
> >> >                         <if test="id != null">
> >> >                                 idStato = #{id}
> >> >                         </if>
> >> >                 </where>
> >> >         </select>
> >> >         <select id="selectById" parameterType="int"
> >> > resultMap="detailStato">
> >> >                 select *
> >> >                 from Stato
> >> >                 WHERE idStato = #{id}
> >> >         </select>
> >> > </mapper>
>
> >> > What is the correct way to address my needs?
>
> >> > Thanks for any help,
> >> > Riccardo
Reply | Threaded
Open this post in threaded view
|

Re: selectByExample is ambiguous in Mapped Statements collection

Maximiliano Juárez Ramos
I think you only have to change the namespace in 'UserMapper.xml'

-    namespace="generics.UserMapper">
+    namespace="com.ibatis.testcase.model.mapper.UserMapper">

saludos


On Mon, Sep 20, 2010 at 5:29 AM, Riccardo <[hidden email]> wrote:
Hello Clinton and Tim,
I have uploaded a sample project to test the problem:
http://code.google.com/p/mybatis/issues/detail?id=112


Reply | Threaded
Open this post in threaded view
|

Re: selectByExample is ambiguous in Mapped Statements collection

Riccardo Cossu
Thanks Maximiliano,
this way it works and actually using the mapper fully qualified name
in the xml mapping is advised at the end of page 7 of the user guide.
What I find strange and a little inconsistent is the fact that, given
there are no duplicate names (so in this case I would use findAllUsers
and findAllProducts instead of findAll) it all works ok using the
"shorthand" namespace (generics.UserMapper).
I find this short namespace very useful when referring mappers from
other namespaces, for the following reason: suppose I have an Invoice
which is related to both User and Product, I would define a mapping
for User in UserMapper.xml and do the same with Product; then I would
refer those mappings in the association mapping of Invoice:

<association resultMap="generics.UserMapper.userDetail"
property="user"..../>
<collection resultMap="generics.ProductMapper.productDetail"
property="products"..../>

Those mappings turn out to be a lot more readable than the ones with
fully qualified names and I don't see why this approach fails, given
the fact that mybatis is able to match those xml to the mapper class
even if their namespace is not equal to the class fully qualified
name.

Bye,
Riccardo
On 21 Set, 04:26, Maximiliano Juárez Ramos <[hidden email]>
wrote:

> I think you only have to change the namespace in 'UserMapper.xml'
>
> -    namespace="generics.UserMapper">
> +    namespace="com.ibatis.testcase.model.mapper.UserMapper">
>
> saludos
>
>
>
> On Mon, Sep 20, 2010 at 5:29 AM, Riccardo <[hidden email]> wrote:
> > Hello Clinton and Tim,
> > I have uploaded a sample project to test the problem:
> >http://code.google.com/p/mybatis/issues/detail?id=112