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
 Assigned to: Gilles Bayon 
    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

Reply via email to