You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@ibatis.apache.org by "Ron Grabowski (JIRA)" <ib...@incubator.apache.org> on 2005/09/09 07:43:31 UTC

[jira] Commented: (IBATISNET-98) Change implementation of IBatisNet.DataMapper.MappedStatements.RunQueryForMap so it works directly with the IDataReader and has support for DictionaryRowDelegate

    [ http://issues.apache.org/jira/browse/IBATISNET-98?page=comments#action_12322996 ] 

Ron Grabowski commented on IBATISNET-98:
----------------------------------------

Gilles fixed this in 225374.

> Change implementation of IBatisNet.DataMapper.MappedStatements.RunQueryForMap so it works directly with the IDataReader and has support for DictionaryRowDelegate
> -----------------------------------------------------------------------------------------------------------------------------------------------------------------
>
>          Key: IBATISNET-98
>          URL: http://issues.apache.org/jira/browse/IBATISNET-98
>      Project: iBatis for .NET
>         Type: Improvement
>     Versions: DataMapper 1.2.1
>     Reporter: Ron Grabowski
>     Assignee: Ron Grabowski
>     Priority: Minor

>
> RunQueryForObject and RunQueryForList interact directly with an IDataReader object to populate the result object. RunQueryForMap does not. The current implementation calls ExecuteQueryForList then iterates through the returned IList to add the items to IDictionary object. The call to ExecuteQueryForList also involves calculating a cache key if caching is enabled. This is unnecessary becuase by the time RunQueryFor* methods are called, the check for the cache should have already taken place. At the very least the current implementation should call RunQueryForList internally to avoid the duplicate cache key calculation. 
> A better implementation would be something similiar to the other RunQueryFor* methods:
>  private IDictionary RunQueryForMap(SNIP)
>  {
>   IDictionary map = new Hashtable();			
>   using (IDbCommand command = _preparedCommand.Create(SNIP))
>   {
>    using (IDataReader reader = command.ExecuteReader())
>    {			
>     while (reader.Read())
>     {
>      object obj = ApplyResultMap(request, reader, null);
>      object key = ObjectProbe.GetPropertyValue(obj, keyProperty);
>      object value = obj;
>      if (valueProperty != null) 
>      {
>       value = ObjectProbe.GetPropertyValue(obj, valueProperty);
>      }
>      map.Add(key, value);
>     }
>    }
>   }
>   return map;
>  }
> That code only makes one iteration through the result set rather than placing everything into an IList then re-iterating through the IList.
> The above implementation could be improved to support a delegate to control how items are added to the IDictionary:
>  // warning: changing name may break existing code...
>  public delegate void ListRowDelegate(object item, IList list);
>  // new!
>  public delegate void DictionaryRowDelegate(object key, object value, IDictionary dictionary);
>  ---
>  // based off of RunQueryForList (this code works...I'm using it now)
>  private IDictionary RunQueryForMap(SNIP)
>  {
>   IDictionary map = new Hashtable();			
>   using (IDbCommand command = _preparedCommand.Create(SNIP))
>   {
>    using (IDataReader reader = command.ExecuteReader())
>    {
>     if (dictionaryRowDelegate != null)
>     {			
>      while (reader.Read() )
>      {
>       object obj = ApplyResultMap(request, reader, null);
>       object key = ObjectProbe.GetPropertyValue(obj, keyProperty);
>       object value = obj;
>       if (valueProperty != null) 
>       {
>        value = ObjectProbe.GetPropertyValue(obj, valueProperty);
>       }
>       map.Add(key, value);
>      }
>      else
>      {
>       while (reader.Read())
>       {
>        object obj = ApplyResultMap(request, reader, null);
>        object key = ObjectProbe.GetPropertyValue(obj, keyProperty);
>        object value = obj;
>        if (valueProperty != null) 
>        {
>         value = ObjectProbe.GetPropertyValue(obj, valueProperty);
>        }
>        dictionaryRowDelegate(key, value, map);
>       }
>      }
>     }
>    }
>   }
>  return map;
>  } 
> The new implementation should mimic ExecuteQueryForRowDelegate (i.e. bypass the cache for the time being). Fixing IBATISNET-87 should also fix the "broken" ExecuteQueryForDictionaryRowDelegate.
> Assuming we had a result set that contained the following data:
>  UserId, PhoneNumber
>  1, 555-1212
>  1, 555-1414
>  1, 214-4757
>  2, 555-7894
>  3, 564-8975
> One could write a DictionaryRowDelegate that would associate user ids to phone numbers (i.e. a simple "groupBy"):
>  private void userIdToPhoneNumbersDelegate(object key, object value, IDictionary dictionary)
>  {
>   int userId = (int)key;
>   string phoneNumber = (string)value;
>   ArrayList phoneNumbers = dictionary[userId] as ArrayList;
>   if (phoneNumbers == null)
>   {
>    phoneNumbers = new ArrayList();
>   }
>   phoneNumbers.Add(phoneNumber);
>   dictionary[userId] = phoneNumbers;
>  }
> Output:
>  ((IList)temp[1]).Count == 3
>  ((IList)temp[2]).Count == 1
>  ((IList)temp[3]).Count == 1

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators:
   http://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see:
   http://www.atlassian.com/software/jira