How to use a strongly typed parameterClass collection?

240 views
Skip to first unread message

in dev

unread,
May 3, 2011, 6:36:02 PM5/3/11
to mybatisnet-user
Suppose I have a strongly typed list that represents the parameters that I would like to pass to my select statement with intention of iterating over the list to build a dynamic query. I have tried setting the parameterClass to equal the fully qualified name of the strongly typed collection (derives from List<ItemType>) and then using the iterate tag to iterate over the collection. The problem is that there is no property field for this type. It is just a collection. Each item would have a property field of course. I have tried to do the following, but without success:
 
<select id="GetUserContext" parameterClass="CriteriaCollection" resultClass="UserContext" listClass="UserContextCollection" resultMap="userContext">
         SELECT u.Id AS UserId, u.EmailAddress AS UserEmail, g.Id AS GroupId, g.Name AS GroupName
         FROM [User] u
         INNER JOIN [GroupUser] gu on gu.User_Id = u.Id
         INNER JOIN [Group] g on g.Id = gu.Group_Id
         WHERE
         <dynamic>
            <iterate open="" close="" conjunction=" " property="this">
               <isEqual prepend="AND" property="#this[].Field#" compareValue="UserId">
                  u.Id = #this[].Value#
               </isEqual>
            </iterate>
         </dynamic>
         IsDeleted = 0
      </select>
 
But since "this" is not a property of CriteriaCollection it throws an exception. Is it possible to pass a list collection, or will I have to have a containing object and refer to the collection as a named property?
for example:
 
<select id="GetUserContext" parameterClass="CriteriaCollectionContainer" resultClass="UserContext" listClass="UserContextCollection" resultMap="userContext">
         SELECT u.Id AS UserId, u.EmailAddress AS UserEmail, g.Id AS GroupId, g.Name AS GroupName
         FROM [User] u
         INNER JOIN [GroupUser] gu on gu.User_Id = u.Id
         INNER JOIN [Group] g on g.Id = gu.Group_Id
         WHERE
         <dynamic>
            <iterate open="" close="" conjunction=" " property="CriteriaCollectionItem">
               <isEqual prepend="AND" property="#CriteriaCollectionItem[].Field#" compareValue="UserId">
                  u.Id = #CriteriaCollectionItem[].Value#
               </isEqual>
            </iterate>
         </dynamic>
         IsDeleted = 0
      </select>
 
I am fairly certain that will work, but I don't like having to place a perfectly good collection in a container object just so that I can refer to it as a named property. Is there any other approach that will work?
 
Sincerely,
 
Indevnow.

Michael McCurrey

unread,
May 3, 2011, 9:35:16 PM5/3/11
to mybatis...@googlegroups.com
I'm not in front of an ide right now; so forgive any syntax errors.  you can definitely pass a straight list as a parameter class, just set your parameterClass to:

parameterClass="list" 


      <dynamic>
            <iterate open="" close="" conjunction=" " >
               <isEqual prepend="AND" property="#[].Field#" compareValue="UserId">
                  u.Id = #[].Value#
               </isEqual>
            </iterate>
         </dynamic>

in dev

unread,
May 4, 2011, 6:55:19 AM5/4/11
to mybatis...@googlegroups.com
Dear Michael,
 
When I pass in my parameterClass collection and use the syntax that you provided I get the following exception:

[2011-05-04 04:50:55,722] ERROR : An exception was caught in public Boolean Contains(String emailAddress, String password)
IBatisNet.Common.Exceptions.ProbeException: Error getting ordinal value from .net object. CauseInput string was not in a correct format. ---> System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   at System.Convert.ToInt32(String value)
   at IBatisNet.Common.Utilities.Objects.ObjectProbe.GetArrayMember(Object obj, String indexedName, AccessorFactory accessorFactory)
   --- End of inner exception stack trace ---

I think that it is failing to index the item in the collection. Not positive though. I suspect that this is a syntax issue. I am playing with the syntax a bit to try and find something that works, but so far no luck. My collection uses .net generics. I hope that is not a factor. It is a List<ICriteria> where ICriteria is a custom interface for the item in the list.
 
Sincerely,
 
indevnow.

Michael McCurrey

unread,
May 4, 2011, 7:57:27 AM5/4/11
to mybatis...@googlegroups.com
I'll give it a run today and post something back unless somebody beats me to it..  Stay tuned

in dev

unread,
May 4, 2011, 2:01:10 PM5/4/11
to mybatis...@googlegroups.com
Dear Michael,
 
One thing that is wrong with the syntax is that the '#' characters should not be present in the property attribute:
<dynamic>
            <iterate open="" close="" conjunction=" " >
               <isEqual prepend="AND" property="#[].Field#" compareValue="UserId">
                  u.Id = #[].Value#
               </isEqual>
            </iterate>
         </dynamic>
 
Should be:
 
<dynamic>
            <iterate open="" close="" conjunction=" " >
               <isEqual prepend="AND" property="[].Field" compareValue="UserId">
                  u.Id = #[].Value#
               </isEqual>
            </iterate>
         </dynamic> 
 
However, even after having made that change I get exactly the same error. I came across a post somewhere that regional settings could be a factor. This might be the issue for me. When I type a question mark in this email you will see that it is an accented e instead:
Do you see the question markÉ
On the other hand that person was not able to parse a string to an int in a unit test. I am successfully parsing strings to numbers using Int32.parse("123");
I will try to fix my regional settings anyway and let you know if that resolves it.
 
Thank you for all of your help.
 
Sincerely,
 
indevnow.

in dev

unread,
May 4, 2011, 2:33:25 PM5/4/11
to mybatis...@googlegroups.com
Dear Michael,
 
I fixed the regional settings by removing the french key mappings using the control panel. Now I can type question marks again. Can you see this??? w00t! Very happy.
Unfortunately I still get exactly the same parsing error. I restarted my IDE just incase the regional settings were not realized by the IDE. I also restarted my browser. I can't wait to get this issue resolved. Thank you so much for your help.
 
Cheers!

in dev

unread,
May 7, 2011, 2:25:24 PM5/7/11
to mybatis...@googlegroups.com
I thought that I would post some more details about this issue today to see if anyone else can reproduce it.
Recap:
I have a collection of criteria that I would like to be able to iterate over adding each criteria to the where clause appropriately. The problem is that MyBatis is throwing an exception when trying
to resolve the index of my collection.

The Exception:


IBatisNet.Common.Exceptions.ProbeException: Error getting ordinal value from .net object. CauseInput string was not in a correct format. ---> System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   at System.Convert.ToInt32(String value)
   at IBatisNet.Common.Utilities.Objects.ObjectProbe.GetArrayMember(Object obj, String indexedName, AccessorFactory accessorFactory)
   --- End of inner exception stack trace ---

   at IBatisNet.Common.Utilities.Objects.ObjectProbe.GetMember(Object obj, String memberName, AccessorFactory accessorFactory)
   at IBatisNet.Common.Utilities.Objects.ObjectProbe.GetMemberValue(Object obj, String memberName, AccessorFactory accessorFactory)
   at IBatisNet.DataMapper.Configuration.Sql.Dynamic.Handlers.ConditionalTagHandler.Compare(SqlTagContext ctx, SqlTag sqlTag, Object parameterObject)
   at IBatisNet.DataMapper.Configuration.Sql.Dynamic.Handlers.IsEqualTagHandler.IsCondition(SqlTagContext ctx, SqlTag tag, Object parameterObject)
   at IBatisNet.DataMapper.Configuration.Sql.Dynamic.Handlers.ConditionalTagHandler.DoStartFragment(SqlTagContext ctx, SqlTag tag, Object parameterObject)
   at IBatisNet.DataMapper.Configuration.Sql.Dynamic.DynamicSql.ProcessBodyChildren(RequestScope request, SqlTagContext ctx, Object parameterObject, IEnumerator localChildren, StringBuilder buffer)
   at IBatisNet.DataMapper.Configuration.Sql.Dynamic.DynamicSql.ProcessBodyChildren(RequestScope request, SqlTagContext ctx, Object parameterObject, IEnumerator localChildren, StringBuilder buffer)
   at IBatisNet.DataMapper.Configuration.Sql.Dynamic.DynamicSql.Process(RequestScope request, Object parameterObject)
   at IBatisNet.DataMapper.Configuration.Sql.Dynamic.DynamicSql.GetRequestScope(IMappedStatement mappedStatement, Object parameterObject, ISqlMapSession session)
   at IBatisNet.DataMapper.MappedStatements.MappedStatement.ExecuteQueryForObject[T](ISqlMapSession session, Object parameterObject, T resultObject)
   at IBatisNet.DataMapper.MappedStatements.MappedStatement.ExecuteQueryForObject[T](ISqlMapSession session, Object parameterObject)
   at IBatisNet.DataMapper.SqlMapper.QueryForObject[T](String statementName, Object parameterObject)

It would be nice if I could see what it was trying to parse. That may give me a hint as to what the problem is.
 
Below are the class definitions for the ICriteriaCollection
 
public interface ICriteria
   {
      String Field { get; set; }
      String Value { get; set; }
   }

 public interface ICriteriaCollection : IList<ICriteria>
   {
   }


<select id="GetUser" parameterClass="ICriteriaCollection" resultClass="User" resultMap="user">


         SELECT u.Id AS UserId, u.EmailAddress AS UserEmail

         FROM [User] u
        
         WHERE
         IsDeleted = 0

         <iterate open=" " close=" " conjunction=" " >
         <isEqual prepend="AND" property="[].Field" compareValue="UserId">
            u.Id = #[].Value#
         </isEqual>
         </iterate>
      </select>
Am I iterating over the collection properlly? Is there something wrong with how I have structured my collections, or how I have used the iterate tag? I have been playing with this for days now and I just can't get past this exception.
 
Thank you for all of your help so far. I really do appreciate it.
 
Sincerely,
 
indevnow.

in dev

unread,
May 7, 2011, 3:23:57 PM5/7/11
to mybatis...@googlegroups.com
I took a peek at the following source code:
 
It looks like the code to resolve the index during iteration is using the following strategy:
int startIndex  = indexedName.IndexOf("[");
int length = indexedName.IndexOf("]");
string name = indexedName.Substring(0, startIndex);
string index = indexedName.Substring( startIndex+1, length-(startIndex+1));
int i = System.Convert.ToInt32(index);
I decided to write some code to test that the System.Convert.ToInt32 method was working correctly on my system, just incase there is a regional setting issue.
I executed the following code successfully:
int i = System.Convert.ToInt32("5");
Then I got to wondering, what if it was not a number, what if it was trying to parse the '.' operator when I am trying to access a property of the list item.
int i = System.Convert.ToInt32(".");
That Threw the following exception:
System.FormatException: Input string was not in a correct format.
   at System.Number.StringToNumber(String str, NumberStyles options, NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
   at System.Number.ParseInt32(String s, NumberStyles style, NumberFormatInfo info)
   at System.Convert.ToInt32(String value)
 
Does mybatis support iterating over a collection of objects? or does it only support iterating over a collection of primitive types? For example, can I iterate over my IList<Icriteria> collection, or is it only legal to iterate over a List of strings?
 
Sincerely,
 
indevnow.


pedrocgsousa

unread,
May 9, 2011, 7:31:28 AM5/9/11
to mybatisnet-user
Hi,

I'm having the same problem.
The problem is on the isEqual tag. I think the tag is no reading
properly the value from "[].Field".
I tried the following:



Parameter class:

public class Xpto
{
private IList<A> lista;
public IList<A> Lista
{
get { return lista; }
}

public Xpto()
{
lista = new List<A>();
}

public class A
{
public int coiso { get; set; }

public A(int val)
{
this.coiso = val;
}
}
}


DAO:

Xpto x = new Xpto();
x.Lista.Add(new Xpto.A(4));
x.Lista.Add(new Xpto.A(3));

IList<Tag> tags = SqlMapper.QueryForList<Tag>("Tag.xpto", x);


SQLMap (without isEqual) => And it works

<select id="xpto" resultMap="FullResultMap" parameterClass="Xpto">
select *
from "tsal"."Tag"
where "Version"
<iterate property="lista" prepend="in" conjunction="," open="("
close=")">
#lista[].coiso#
</iterate>aa
</select>


SQLMap (without isEqual) => Doesn't work

<select id="xpto" resultMap="FullResultMap" parameterClass="Xpto">
select *
from "tsal"."Tag"
where "Version"
<iterate property="lista" prepend="in" conjunction="," open="("
close=")">
<isEqual property="lista[].coiso" compareValue="3" >
#lista[].coiso#
</isEqual>
</iterate>aa
</select>

Error:

===================================

Error getting ordinal value from .net object. CauseInput string was
not in a correct format. (IBatisNet.Common)

------------------------------
Program Location:

at IBatisNet.Common.Utilities.Objects.ObjectProbe.GetMember(Object
obj, String memberName, AccessorFactory accessorFactory)
at
IBatisNet.Common.Utilities.Objects.ObjectProbe.GetMemberValue(Object
obj, String memberName, AccessorFactory accessorFactory)
at
IBatisNet.DataMapper.Configuration.Sql.Dynamic.Handlers.ConditionalTagHandler.Compare(SqlTagContext
ctx, SqlTag sqlTag, Object parameterObject)
at
IBatisNet.DataMapper.Configuration.Sql.Dynamic.Handlers.IsEqualTagHandler.IsCondition(SqlTagContext
ctx, SqlTag tag, Object parameterObject)
at
IBatisNet.DataMapper.Configuration.Sql.Dynamic.Handlers.ConditionalTagHandler.DoStartFragment(SqlTagContext
ctx, SqlTag tag, Object parameterObject)
at
IBatisNet.DataMapper.Configuration.Sql.Dynamic.DynamicSql.ProcessBodyChildren(RequestScope
request, SqlTagContext ctx, Object parameterObject, IEnumerator
localChildren, StringBuilder buffer)
at
IBatisNet.DataMapper.Configuration.Sql.Dynamic.DynamicSql.ProcessBodyChildren(RequestScope
request, SqlTagContext ctx, Object parameterObject, IEnumerator
localChildren, StringBuilder buffer)
at
IBatisNet.DataMapper.Configuration.Sql.Dynamic.DynamicSql.ProcessBodyChildren(RequestScope
request, SqlTagContext ctx, Object parameterObject, IList
localChildren)
at
IBatisNet.DataMapper.Configuration.Sql.Dynamic.DynamicSql.Process(RequestScope
request, Object parameterObject)
at
IBatisNet.DataMapper.Configuration.Sql.Dynamic.DynamicSql.GetRequestScope(IMappedStatement
mappedStatement, Object parameterObject, ISqlMapSession session)
at
IBatisNet.DataMapper.MappedStatements.MappedStatement.ExecuteQueryForList[T]
(ISqlMapSession session, Object parameterObject)
at IBatisNet.DataMapper.SqlMapper.QueryForList[T](String
statementName, Object parameterObject)
at
Telbit.TeStudio.DbService.Model.Dao.TagDao.SelectByExample(TagExample
example) in E:\repos\testudio\tsal_rm_1824_forcing
\Telbit.TeStudio.DbService\Model\Dao\TagDao.cs:line 21
at
Telbit.TeStudio.DbService.Service.TsalService.GetTestHistory(String
id) in E:\repos\testudio\tsal_rm_1824_forcing\Telbit.TeStudio.DbService
\Service\TsalService.cs:line 24
at
_dynamic_Telbit.TeStudio.DbService.Service.TsalService.GetTestHistory(Object ,
Object[] )
at Spring.Reflection.Dynamic.SafeMethod.Invoke(Object target,
Object[] arguments) in l:\projects\spring-net\trunk\src\Spring
\Spring.Core\Reflection\Dynamic\DynamicMethod.cs:line 156
at Spring.Aop.Framework.DynamicMethodInvocation.InvokeJoinpoint()
in l:\projects\spring-net\trunk\src\Spring\Spring.Aop\Aop\Framework
\DynamicMethodInvocation.cs:line 100
at Spring.Aop.Framework.AbstractMethodInvocation.Proceed() in l:
\projects\spring-net\trunk\src\Spring\Spring.Aop\Aop\Framework
\AbstractMethodInvocation.cs:line 259
at
Spring.Transaction.Interceptor.TransactionInterceptor.Invoke(IMethodInvocation
invocation) in l:\projects\spring-net\trunk\src\Spring\Spring.Data
\Transaction\Interceptor\TransactionInterceptor.cs:line 86
at Spring.Aop.Framework.AbstractMethodInvocation.Proceed() in l:
\projects\spring-net\trunk\src\Spring\Spring.Aop\Aop\Framework
\AbstractMethodInvocation.cs:line 284
at Spring.Aop.Framework.DynamicProxy.AdvisedProxy.Invoke(Object
proxy, Object target, Type targetType, MethodInfo targetMethod,
MethodInfo proxyMethod, Object[] args, IList interceptors) in l:
\projects\spring-net\trunk\src\Spring\Spring.Aop\Aop\Framework
\DynamicProxy\AdvisedProxy.cs:line 217
at
CompositionAopProxy_a546c8315d254477b22755443691c0d9.GetTestHistory(String
id)
at Telbit.TeStudio.View.Program.SetupSpring() in E:\repos\testudio
\tsal_rm_1824_forcing\Telbit.TeStudio\Program.cs:line 257
at Telbit.TeStudio.View.Program.Main(String[] args) in E:\repos
\testudio\tsal_rm_1824_forcing\Telbit.TeStudio\Program.cs:line 57

===================================

Input string was not in a correct format. (mscorlib)

------------------------------
Program Location:

at System.Number.StringToNumber(String str, NumberStyles options,
NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
at System.Number.ParseInt32(String s, NumberStyles style,
NumberFormatInfo info)
at System.Convert.ToInt32(String value)
at
IBatisNet.Common.Utilities.Objects.ObjectProbe.GetArrayMember(Object
obj, String indexedName, AccessorFactory accessorFactory)






On May 7, 8:23 pm, in dev <indev...@gmail.com> wrote:
> I took a peek at the following source code:http://www.java2s.com/Open-Source/CSharp/Persistence-Frameworks/iBATI...
>
> It looks like the code to resolve the index during iteration is using the
> following strategy:
> *int* startIndex  = indexedName.IndexOf("[");
> *int* length = indexedName.IndexOf("]");
> *string* name = indexedName.Substring(0, startIndex);
> *string* index = indexedName.Substring( startIndex+1,
> length-(startIndex+1));
> *int* i = System.Convert.ToInt32(index);
> I decided to write some code to test that the System.Convert.ToInt32 method
> was working correctly on my system, just incase there is a regional setting
> issue.
> I executed the following code successfully:
> *int* i = System.Convert.ToInt32("5");
> Then I got to wondering, what if it was not a number, what if it was trying
> to parse the '.' operator when I am trying to access a property of the list
> item.
> *int* i = System.Convert.ToInt32(".");
> That Threw the following exception:
> System.FormatException: Input string was not in a correct format.
>    at System.Number.StringToNumber(String str, NumberStyles options,
> NumberBuffer& number, NumberFormatInfo info, Boolean parseDecimal)
>    at System.Number.ParseInt32(String s, NumberStyles style,
> NumberFormatInfo info)
>    at System.Convert.ToInt32(String value)
>
> Does mybatis support iterating over a collection of objects? or does it only
> support iterating over a collection of primitive types? For example, can I
> iterate over my IList<Icriteria> collection, or is it only legal to iterate
> over a List of strings?
>
> Sincerely,
>
> indevnow.
>
> >   On Wed, May 4, 2011 at 12:33 PM, in dev <indev...@gmail.com> wrote:
>
> >> Dear Michael,
>
> >> I fixed the regional settings by removing the french key mappings using
> >> the control panel. Now I can type question marks again. Can you see this???
> >> w00t! Very happy.
> >> Unfortunately I still get exactly the same parsing error. I restarted my
> >> IDE just incase the regional settings were not realized by the IDE. I also
> >> restarted my browser. I can't wait to get this issue resolved. Thank you so
> >> much for your help.
>
> >> Cheers!
>
> >>> On Wed, May 4, 2011 at 5:57 AM, Michael McCurrey <mmccur...@gmail.com>wrote:
>
> >>>> I'll give it a run today and post something back unless somebody beats
> >>>> me to it..  Stay tuned
>
> >>>>> On Tue, May 3, 2011 at 7:35 PM, Michael McCurrey <mmccur...@gmail.com>wrote:
>
> >>>>>> I'm not in front of an ide right now; so forgive any syntax errors.
> >>>>>>  you can definitely pass a straight list as a parameter class, just set your
> >>>>>> parameterClass to:
>
> >>>>>> parameterClass="list"
>
> >>>>>>        <dynamic>
> >>>>>>             <iterate open="" close="" conjunction=" " >
>
> >>>>>>                <isEqual
>
> ...
>
> read more »
Reply all
Reply to author
Forward
0 new messages