|
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 |
|
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 |
|
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 |
|
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 > |
|
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 |
|
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, |
|
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 |
| Powered by Nabble | Edit this page |
