You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user-cs@ibatis.apache.org by Rencelj Marco <re...@cad.it> on 2005/11/11 09:02:06 UTC
Error in using an ArrayList type as resultClass in IBatis for .net
I had to get a list with a variable number of columns so I had to try
ArrayList as resultClass (columns are unnamed).
The ArrayList is populated with a correct number of rows but each row
instance is an empty ArrayList.
I fixed the problem in source code adding a code fragment in
MappedStatement.cs as in included code.
Anybody had the same problem? May be there is a release that include
this fix ...
Thanks in advance
Marco
...
namespace IBatisNet.DataMapper.MappedStatements
{
/// <summary>
/// Summary description for MappedStatement.
/// </summary>
public class MappedStatement : IMappedStatement
{
...
/// <summary>
///
/// </summary>
/// <param name="request"></param>
/// <param name="reader"></param>
/// <param name="resultObject"></param>
/// <returns></returns>
private object ApplyResultMap(RequestScope request,
IDataReader reader, object resultObject)
{
object outObject = resultObject;
// If there's an ResultMap, use it
if (request.ResultMap != null)
{
ResultMap resultMap =
request.GetResultMap(reader);
if (outObject == null)
{
outObject =
resultMap.CreateInstanceOfResult();
}
// For each Property in the ResultMap, set the
property in the object
foreach(DictionaryEntry entry in
resultMap.ColumnsToPropertiesMap)
{
ResultProperty property =
(ResultProperty)entry.Value;
SetObjectProperty(request, resultMap,
property, ref outObject, reader);
}
}
else // else try to use a ResultClass
{
if (_statement.ResultClass != null)
{
if (outObject == null)
{
outObject =
_statement.CreateInstanceOfResultClass();
}
// Check if the ResultClass is a
'primitive' Type
if
(_sqlMap.TypeHandlerFactory.IsSimpleType(_statement.ResultClass))
{
// Create a ResultMap
ResultMap resultMap = new
ResultMap();
// Create a ResultProperty
ResultProperty property = new
ResultProperty();
property.PropertyName = "value";
property.ColumnIndex = 0;
property.TypeHandler =
_sqlMap.TypeHandlerFactory.GetTypeHandler(outObject.GetType());
resultMap.AddResultPropery(property);
SetObjectProperty(request,
request.ResultMap, property, ref outObject, reader);
}
else if (outObject is Hashtable)
{
for (int i = 0; i <
reader.FieldCount; i++)
{
string columnName =
reader.GetName(i);
((Hashtable)
outObject).Add(columnName, reader.GetValue(i));
}
}
// added code from here !
else if (outObject is ArrayList)
{
for (int i = 0; i <
reader.FieldCount; i++)
{
string columnName =
reader.GetName(i);
((ArrayList)
outObject).Add(reader.GetValue(i));
}
}
// end of added code !
else
{
AutoMapReader( reader, ref
outObject);
}
}
}
return outObject;
}
/// <summary>
/// Retrieve the output parameter and map them on the result
object.
/// This routine is only use is you specified a ParameterMap
and some output attribute
/// or if you use a store procedure with output parameter...
/// </summary>
/// <param name="request"></param>
/// <param name="session">The current session.</param>
/// <param name="result">The result object.</param>
/// <param name="command">The command sql.</param>
private void RetrieveOutputParameters(RequestScope request,
IDalSession session, IDbCommand command, object result)
{
if (request.ParameterMap != null)
{
for(int i=0;
i<request.ParameterMap.PropertiesList.Count; i++)
{
ParameterProperty mapping =
request.ParameterMap.GetProperty(i);
if (mapping.Direction ==
ParameterDirection.Output ||
mapping.Direction ==
ParameterDirection.InputOutput)
{
string parameterName = string.Empty;
if
(session.DataSource.Provider.UseParameterPrefixInParameter == false)
{
parameterName =
mapping.ColumnName;
}
else
{
parameterName =
session.DataSource.Provider.ParameterPrefix +
mapping.ColumnName;
}
if (mapping.TypeHandler == null) //
Find the TypeHandler
{
lock(mapping)
{
if (mapping.TypeHandler
== null)
{
Type propertyType
=ObjectProbe.GetPropertyTypeForGetter(result,mapping.PropertyName);
mapping.TypeHandler =
_sqlMap.TypeHandlerFactory.GetTypeHandler(propertyType);
}
}
}
object dataBaseValue =
mapping.TypeHandler.GetDataBaseValue(
((IDataParameter)command.Parameters[parameterName]).Value,
result.GetType() );
ObjectProbe.SetPropertyValue(result,
mapping.PropertyName, dataBaseValue);
}
}
}
}
#region ExecuteForObject
/// <summary>
/// Executes an SQL statement that returns a single row as
an Object.
/// </summary>
/// <param name="session">The session used to execute the
statement.</param>
/// <param name="parameterObject">The object used to set the
parameters in the SQL.</param>
/// <returns>The object</returns>
public virtual object ExecuteQueryForObject( IDalSession
session, object parameterObject )
{
return ExecuteQueryForObject(session, parameterObject,
null);
}
/// <summary>
/// Executes an SQL statement that returns a single row as
an Object of the type of
/// the resultObject passed in as a parameter.
/// </summary>
/// <param name="session">The session used to execute the
statement.</param>
/// <param name="parameterObject">The object used to set the
parameters in the SQL.</param>
/// <param name="resultObject">The result object.</param>
/// <returns>The object</returns>
public virtual object ExecuteQueryForObject(IDalSession
session, object parameterObject, object resultObject )
{
object obj = null;
RequestScope request =
_statement.Sql.GetRequestScope(parameterObject, session);;
if (_statement.CacheModel == null)
{
obj = RunQueryForObject(request, session,
parameterObject, resultObject);
}
else
{
CacheKey key = null;
if (_statement.ParameterMap != null)
{
key = new
CacheKey(_sqlMap.TypeHandlerFactory, this.Name,
request.PreparedStatement.PreparedSql,
parameterObject,
request.ParameterMap.GetPropertyNameArray(),
NO_SKIPPED_RESULTS,
NO_MAXIMUM_RESULTS,
CacheKeyType.Object);
}
else
{
key = new
CacheKey(_sqlMap.TypeHandlerFactory, this.Name,
request.PreparedStatement.PreparedSql,
parameterObject,
new string[0],
NO_SKIPPED_RESULTS,
NO_MAXIMUM_RESULTS,
CacheKeyType.Object);
}
obj = _statement.CacheModel[key];
if (obj == null)
{
obj = RunQueryForObject(request, session,
parameterObject, resultObject);
_statement.CacheModel[key] = obj;
}
}
return obj;
}
/// <summary>
/// Executes an SQL statement that returns a single row as
an Object of the type of
/// the resultObject passed in as a parameter.
/// </summary>
/// <param name="request">The request scope.</param>
/// <param name="session">The session used to execute the
statement.</param>
/// <param name="parameterObject">The object used to set the
parameters in the SQL.</param>
/// <param name="resultObject">The result object.</param>
/// <returns>The object</returns>
private object RunQueryForObject(RequestScope request,
IDalSession session, object parameterObject, object resultObject )
{
object result = resultObject;
//using ( IDbCommand command =
CreatePreparedCommand(request, session, parameterObject ))
using ( IDbCommand command = _preparedCommand.Create(
request, session, this.Statement, parameterObject ) )
{
using ( IDataReader reader =
command.ExecuteReader() )
{
if ( reader.Read() )
{
result = ApplyResultMap(request,
reader, resultObject);
}
}
ExecutePostSelect( session, request);
#region remark
// If you are using the OleDb data provider (as
you are), you need to close the
// DataReader before output parameters are
visible.
#endregion
RetrieveOutputParameters(request, session,
command, parameterObject);
}
return result;
}
#endregion
#region ExecuteQueryForList
/// <summary>
/// Runs a query with a custom object that gets a chance
/// to deal with each row as it is processed.
/// </summary>
/// <param name="session">The session used to execute the
statement.</param>
/// <param name="parameterObject">The object used to set the
parameters in the SQL.</param>
/// <param name="rowDelegate"></param>
public virtual IList ExecuteQueryForRowDelegate( IDalSession
session, object parameterObject, SqlMapper.RowDelegate rowDelegate )
{
RequestScope request =
_statement.Sql.GetRequestScope(parameterObject, session);;
if (rowDelegate == null)
{
throw new DataMapperException("A null
RowDelegate was passed to QueryForRowDelegate.");
}
return RunQueryForList(request, session,
parameterObject, NO_SKIPPED_RESULTS, NO_MAXIMUM_RESULTS, rowDelegate);
}
/// <summary>
/// Executes the SQL and retuns all rows selected. This is
exactly the same as
/// calling ExecuteQueryForList(session, parameterObject,
NO_SKIPPED_RESULTS, NO_MAXIMUM_RESULTS).
/// </summary>
/// <param name="session">The session used to execute the
statement.</param>
/// <param name="parameterObject">The object used to set the
parameters in the SQL.</param>
/// <returns>A List of result objects.</returns>
public virtual IList ExecuteQueryForList( IDalSession
session, object parameterObject )
{
return ExecuteQueryForList( session, parameterObject,
NO_SKIPPED_RESULTS, NO_MAXIMUM_RESULTS);
}
/// <summary>
/// Executes the SQL and retuns a subset of the rows
selected.
/// </summary>
/// <param name="session">The session used to execute the
statement.</param>
/// <param name="parameterObject">The object used to set the
parameters in the SQL.</param>
/// <param name="skipResults">The number of rows to skip
over.</param>
/// <param name="maxResults">The maximum number of rows to
return.</param>
/// <returns>A List of result objects.</returns>
public virtual IList ExecuteQueryForList( IDalSession
session, object parameterObject, int skipResults, int maxResults )
{
IList list = null;
RequestScope request =
_statement.Sql.GetRequestScope(parameterObject, session);;
if (_statement.CacheModel == null)
{
list = RunQueryForList(request, session,
parameterObject, skipResults, maxResults, null);
}
else
{
CacheKey key = null;
if (_statement.ParameterMap != null)
{
key = new
CacheKey(_sqlMap.TypeHandlerFactory, this.Name,
request.PreparedStatement.PreparedSql,
parameterObject,
request.ParameterMap.GetPropertyNameArray(),
skipResults,
maxResults,
CacheKeyType.List);
}
else
{
key = new
CacheKey(_sqlMap.TypeHandlerFactory, this.Name,
request.PreparedStatement.PreparedSql,
parameterObject,
new string[0],
skipResults,
maxResults,
CacheKeyType.List);
}
list = (IList)_statement.CacheModel[key];
if (list == null)
{
list = RunQueryForList(request, session,
parameterObject, skipResults, maxResults, null);
_statement.CacheModel[key] = list;
}
}
return list;
}
/// <summary>
/// Executes the SQL and retuns a List of result objects.
/// </summary>
/// <param name="request">The request scope.</param>
/// <param name="session">The session used to execute the
statement.</param>
/// <param name="parameterObject">The object used to set the
parameters in the SQL.</param>
/// <param name="skipResults">The number of rows to skip
over.</param>
/// <param name="maxResults">The maximum number of rows to
return.</param>
/// <param name="rowDelegate"></param>
/// <returns>A List of result objects.</returns>
private IList RunQueryForList(RequestScope request,
IDalSession session, object parameterObject, int skipResults, int
maxResults, SqlMapper.RowDelegate rowDelegate)
{
IList list = null;
//using ( IDbCommand command =
CreatePreparedCommand(request, session, parameterObject ))
using ( IDbCommand command = _preparedCommand.Create(
request, session, this.Statement, parameterObject ) )
{
if (_statement.ListClass == null)
{
list = new ArrayList();
}
else
{
list =
_statement.CreateInstanceOfListClass();
}
using ( IDataReader reader =
command.ExecuteReader() )
{
// skip results
for (int i = 0; i < skipResults; i++)
{
if (!reader.Read())
{
break;
}
}
int n = 0;
if (rowDelegate == null)
{
while ( (maxResults ==
NO_MAXIMUM_RESULTS || n < maxResults)
&& reader.Read() )
{
object obj =
ApplyResultMap(request, reader, null);
list.Add( obj );
n++;
}
}
else
{
while ( (maxResults ==
NO_MAXIMUM_RESULTS || n < maxResults)
&& reader.Read() )
{
object obj =
ApplyResultMap(request, reader, null);
rowDelegate(obj, list);
n++;
}
}
}
ExecutePostSelect( session, request);
RetrieveOutputParameters(request, session,
command, parameterObject);
}
return list;
}
/// <summary>
/// Executes the SQL and and fill a strongly typed
collection.
/// </summary>
/// <param name="session">The session used to execute the
statement.</param>
/// <param name="parameterObject">The object used to set the
parameters in the SQL.</param>
/// <param name="resultObject">A strongly typed collection
of result objects.</param>
public virtual void ExecuteQueryForList(IDalSession session,
object parameterObject, IList resultObject )
{
RequestScope request =
_statement.Sql.GetRequestScope(parameterObject, session);;
//using ( IDbCommand command =
CreatePreparedCommand(request, session, parameterObject ) )
using ( IDbCommand command = _preparedCommand.Create(
request, session, this.Statement, parameterObject ) )
{
using ( IDataReader reader =
command.ExecuteReader() )
{
while ( reader.Read() )
{
object obj = ApplyResultMap(request,
reader, null);
resultObject.Add( obj );
}
}
ExecutePostSelect( session, request);
RetrieveOutputParameters(request, session,
command, parameterObject);
}
}
#endregion
#region ExecuteUpdate, ExecuteInsert
/// <summary>
/// Execute an update statement. Also used for delete
statement.
/// Return the number of row effected.
/// </summary>
/// <param name="session">The session used to execute the
statement.</param>
/// <param name="parameterObject">The object used to set the
parameters in the SQL.</param>
/// <returns>The number of row effected.</returns>
public virtual int ExecuteUpdate(IDalSession session, object
parameterObject )
{
int rows = 0; // the number of rows affected
RequestScope request =
_statement.Sql.GetRequestScope(parameterObject, session);;
//using (IDbCommand command =
CreatePreparedCommand(request, session, parameterObject ))
using ( IDbCommand command = _preparedCommand.Create(
request, session, this.Statement, parameterObject ) )
{
rows = command.ExecuteNonQuery();
ExecutePostSelect( session, request);
RetrieveOutputParameters(request, session,
command, parameterObject);
}
RaiseExecuteEvent();
return rows;
}
/// <summary>
/// Execute an insert statement. Fill the parameter object
with
/// the ouput parameters if any, also could return the
insert generated key
/// </summary>
/// <param name="session">The session</param>
/// <param name="parameterObject">The parameter object used
to fill the statement.</param>
/// <returns>Can return the insert generated key.</returns>
public virtual object ExecuteInsert(IDalSession session,
object parameterObject )
{
object generatedKey = null;
SelectKey selectKeyStatement = null;
RequestScope request =
_statement.Sql.GetRequestScope(parameterObject, session);;
if (_statement is Insert)
{
selectKeyStatement =
((Insert)_statement).SelectKey;
}
if (selectKeyStatement != null &&
!selectKeyStatement.isAfter)
{
MappedStatement mappedStatement =
_sqlMap.GetMappedStatement( selectKeyStatement.Id );
generatedKey =
mappedStatement.ExecuteQueryForObject(session, parameterObject);
ObjectProbe.SetPropertyValue(parameterObject,
selectKeyStatement.PropertyName, generatedKey);
}
//using (IDbCommand command =
CreatePreparedCommand(request, session, parameterObject ))
using ( IDbCommand command = _preparedCommand.Create(
request, session, this.Statement, parameterObject ) )
{
if (_statement is Insert)
{
command.ExecuteNonQuery();
}
else
{
generatedKey = command.ExecuteScalar();
if ( (_statement.ResultClass!=null) &&
_sqlMap.TypeHandlerFactory.IsSimpleType(_statement.ResultClass) )
{
ITypeHandler typeHandler =
_sqlMap.TypeHandlerFactory.GetTypeHandler(_statement.ResultClass);
generatedKey =
typeHandler.GetDataBaseValue(generatedKey, _statement.ResultClass);
}
}
if (selectKeyStatement != null &&
selectKeyStatement.isAfter)
{
MappedStatement mappedStatement =
_sqlMap.GetMappedStatement( selectKeyStatement.Id );
generatedKey =
mappedStatement.ExecuteQueryForObject(session, parameterObject);
ObjectProbe.SetPropertyValue(parameterObject,
selectKeyStatement.PropertyName, generatedKey);
}
ExecutePostSelect( session, request);
RetrieveOutputParameters(request, session,
command, parameterObject);
}
RaiseExecuteEvent();
return generatedKey;
}
#endregion
#region ExecuteQueryForMap
/// <summary>
/// Executes the SQL and retuns all rows selected in a map
that is keyed on the property named
/// in the keyProperty parameter. The value at each key
will be the value of the property specified
/// in the valueProperty parameter. If valueProperty is
null, the entire result object will be entered.
/// </summary>
/// <param name="session">
/// The session used to execute the statement
/// </param>
/// <param name="parameterObject">
/// The object used to set the parameters in the SQL.
/// </param>
/// <param name="keyProperty">
/// The property of the result object to be used as the key.
/// </param>
/// <param name="valueProperty">
/// The property of the result object to be used as the
value (or null)
/// </param>
/// <returns>A hashtable of object containing the rows keyed
by keyProperty.</returns>
///<exception cref="DataMapperException">
///If a transaction is not in progress, or the database
throws an exception.
///</exception>
public virtual IDictionary ExecuteQueryForMap( IDalSession
session, object parameterObject, string keyProperty, string
valueProperty )
{
IDictionary map = new Hashtable();
RequestScope request =
_statement.Sql.GetRequestScope(parameterObject, session);;
if (_statement.CacheModel == null)
{
map = RunQueryForMap(request, session,
parameterObject, keyProperty, valueProperty );
}
else
{
CacheKey key = null;
if (_statement.ParameterMap != null)
{
key = new
CacheKey(_sqlMap.TypeHandlerFactory, this.Name,
request.PreparedStatement.PreparedSql,
parameterObject,
request.ParameterMap.GetPropertyNameArray(),
NO_SKIPPED_RESULTS,
NO_MAXIMUM_RESULTS,
CacheKeyType.Map);
}
else
{
key = new
CacheKey(_sqlMap.TypeHandlerFactory, this.Name,
request.PreparedStatement.PreparedSql,
parameterObject,
new string[0],
NO_SKIPPED_RESULTS,
NO_MAXIMUM_RESULTS,
CacheKeyType.Map);
}
map = (IDictionary)_statement.CacheModel[key];
if (map == null)
{
map = RunQueryForMap( request, session,
parameterObject, keyProperty, valueProperty );
_statement.CacheModel[key] = map;
}
}
return map;
}
/// <summary>
/// Executes the SQL and retuns all rows selected in a map
that is keyed on the property named
/// in the keyProperty parameter. The value at each key
will be the value of the property specified
/// in the valueProperty parameter. If valueProperty is
null, the entire result object will be entered.
/// </summary>
/// <param name="request">The request scope.</param>
/// <param name="session">The session used to execute the
statement</param>
/// <param name="parameterObject">The object used to set the
parameters in the SQL.</param>
/// <param name="keyProperty">The property of the result
object to be used as the key.</param>
/// <param name="valueProperty">The property of the result
object to be used as the value (or null)</param>
/// <returns>A hashtable of object containing the rows keyed
by keyProperty.</returns>
///<exception cref="DataMapperException">If a transaction is
not in progress, or the database throws an exception.</exception>
private IDictionary RunQueryForMap( RequestScope request,
IDalSession session,
object parameterObject, string keyProperty, string
valueProperty )
{
IDictionary map = new Hashtable();
IList list = ExecuteQueryForList(session,
parameterObject);
for(int i =0; i<list.Count; i++)
{
object obj = list[i];
if (obj != null)
{
object key =
ObjectProbe.GetPropertyValue(obj, keyProperty);
object value = obj;
if (valueProperty != null)
{
value =
ObjectProbe.GetPropertyValue(obj, valueProperty);
}
map.Add(key, value);
}
}
return map;
}
#endregion
/// <summary>
/// Process 'select' result properties
/// </summary>
/// <param name="request"></param>
/// <param name="session"></param>
private void ExecutePostSelect(IDalSession session,
RequestScope request)
{
while (request.QueueSelect.Count>0)
{
PostBindind postSelect =
request.QueueSelect.Dequeue() as PostBindind;
if (postSelect.Method ==
ExecuteMethod.ExecuteQueryForIList)
{
object values =
postSelect.Statement.ExecuteQueryForList(session, postSelect.Keys);
ObjectProbe.SetPropertyValue(
postSelect.Target, postSelect.ResultProperty.PropertyName, values);
}
else if (postSelect.Method ==
ExecuteMethod.ExecuteQueryForStrongTypedIList)
{
object values =
Activator.CreateInstance(postSelect.ResultProperty.PropertyInfo.Property
Type);
postSelect.Statement.ExecuteQueryForList(session, postSelect.Keys,
(IList)values);
ObjectProbe.SetPropertyValue(
postSelect.Target, postSelect.ResultProperty.PropertyName, values);
}
if (postSelect.Method ==
ExecuteMethod.ExecuteQueryForArrayList)
{
IList values =
postSelect.Statement.ExecuteQueryForList(session, postSelect.Keys);
Type elementType =
postSelect.ResultProperty.PropertyInfo.PropertyType.GetElementType();
Array array =
Array.CreateInstance(elementType, values.Count);
for(int i=0;i<values.Count;i++)
{
array.SetValue(values[i],i);
}
postSelect.ResultProperty.PropertyInfo.SetValue(postSelect.Target,
array, null);
}
else if (postSelect.Method ==
ExecuteMethod.ExecuteQueryForObject)
{
object value =
postSelect.Statement.ExecuteQueryForObject(session, postSelect.Keys);
ObjectProbe.SetPropertyValue(
postSelect.Target, postSelect.ResultProperty.PropertyName, value);
}
}
}
/// <summary>
///
/// </summary>
/// <param name="request"></param>
/// <param name="resultMap"></param>
/// <param name="mapping"></param>
/// <param name="target"></param>
/// <param name="reader"></param>
private void SetObjectProperty(RequestScope request,
ResultMap resultMap,
ResultProperty mapping, ref object target, IDataReader
reader)
{
string selectStatement = mapping.Select;
if (selectStatement.Length == 0 &&
mapping.NestedResultMap == null)
{
// If the property is not a 'select'
ResultProperty
// or a 'resultMap'
ResultProperty
// We have a 'normal' ResultMap
#region Not a select statement
if (mapping.TypeHandler == null) // Find the
TypeHandler
{
lock(mapping)
{
if (mapping.TypeHandler == null)
{
int columnIndex = 0;
if (mapping.ColumnIndex ==
ResultProperty.UNKNOWN_COLUMN_INDEX)
{
columnIndex =
reader.GetOrdinal(mapping.ColumnName);
}
else
{
columnIndex =
mapping.ColumnIndex;
}
Type systemType
=((IDataRecord)reader).GetFieldType(columnIndex);
mapping.TypeHandler =
_sqlMap.TypeHandlerFactory.GetTypeHandler(systemType);
}
}
}
object dataBaseValue = mapping.GetDataBaseValue(
reader );
if (resultMap != null)
{
resultMap.SetValueOfProperty( ref target,
mapping, dataBaseValue );
}
else
{
MappedStatement.SetValueOfProperty( ref
target, mapping, dataBaseValue );
}
#endregion
}
else if (mapping.NestedResultMap != null) //
'resultMap' ResultProperty
{
object obj = null;
obj =
mapping.NestedResultMap.CreateInstanceOfResult();
FillObjectWithReaderAndResultMap(request,
reader, mapping.NestedResultMap, obj);
MappedStatement.SetValueOfProperty( ref target,
mapping, obj );
}
else //'select' ResultProperty
{
// Get the select statement
MappedStatement queryStatement =
_sqlMap.GetMappedStatement(selectStatement);
string paramString = mapping.ColumnName;
object keys = null;
bool wasNull = false;
#region Find Key(s)
if (paramString.IndexOf(',')>0 ||
paramString.IndexOf('=')>0) // composite parameters key
{
IDictionary keyMap = new Hashtable();
keys = keyMap;
// define which character is seperating
fields
char[] splitter = {'=',','};
string[] paramTab =
paramString.Split(splitter);
if (paramTab.Length % 2 != 0)
{
throw new
DataMapperException("Invalid composite key string format in
'"+mapping.PropertyName+". It must be:
property1=column1,property2=column2,...");
}
IEnumerator enumerator =
paramTab.GetEnumerator();
while (!wasNull && enumerator.MoveNext())
{
string hashKey =
((string)enumerator.Current).Trim();
enumerator.MoveNext();
object hashValue = reader.GetValue(
reader.GetOrdinal(((string)enumerator.Current).Trim()) );
keyMap.Add(hashKey, hashValue );
wasNull = (hashValue ==
System.DBNull.Value);
}
}
else // single parameter key
{
keys =
reader.GetValue(reader.GetOrdinal(paramString));
wasNull =
reader.IsDBNull(reader.GetOrdinal(paramString));
}
#endregion
if (wasNull)
{
// set the value of an object property to
null
ObjectProbe.SetPropertyValue(target,
mapping.PropertyName, null);
}
else // Collection object or .Net object
{
PostBindind postSelect = new
PostBindind();
postSelect.Statement = queryStatement;
postSelect.Keys = keys;
postSelect.Target = target;
postSelect.ResultProperty = mapping;
#region Collection object or .NET object
// Check if the object to Map implement
'IList' or is IList type
// If yes the ResultProperty is map to a
IList object
if (
(mapping.PropertyInfo.PropertyType.GetInterface("IList") != null) ||
(mapping.PropertyInfo.PropertyType
== typeof(IList)))
{
object values = null;
if (mapping.IsLazyLoad)
{
values =
LazyLoadList.NewInstance(_sqlMap.DataSource, queryStatement, keys,
target, mapping.PropertyName);
ObjectProbe.SetPropertyValue(
target, mapping.PropertyName, values);
}
else
{
if
(mapping.PropertyInfo.PropertyType == typeof(IList))
{
postSelect.Method =
ExecuteMethod.ExecuteQueryForIList;
}
else
{
postSelect.Method =
ExecuteMethod.ExecuteQueryForStrongTypedIList;
}
}
}
else if
(mapping.PropertyInfo.PropertyType.IsArray)
{
postSelect.Method =
ExecuteMethod.ExecuteQueryForArrayList;
}
else // The ResultProperty is map to a
.Net object
{
postSelect.Method =
ExecuteMethod.ExecuteQueryForObject;
}
#endregion
if (!mapping.IsLazyLoad)
{
request.QueueSelect.Enqueue(postSelect);
}
}
}
}
private static void SetValueOfProperty( ref object target,
ResultProperty property, object dataBaseValue )
{
if (target is Hashtable)
{
((Hashtable) target).Add(property.PropertyName,
dataBaseValue);
}
else
{
if (property.PropertyName == "value")
{
target = dataBaseValue;
}
else
{
if (dataBaseValue == null)
{
if (property.PropertyInfo != null)
{
property.PropertyInfo.SetValue( target, null, null );
}
else
{
ObjectProbe.SetPropertyValue(
target, property.PropertyName, null);
}
}
else
{
if (property.PropertyInfo != null)
{
property.PropertyInfo.SetValue( target, dataBaseValue, null );
}
else
{
ObjectProbe.SetPropertyValue(
target, property.PropertyName, dataBaseValue);
}
}
}
}
}
/// <summary>
/// Raise an event ExecuteEventArgs
/// (Used when a query is executed)
/// </summary>
private void RaiseExecuteEvent()
{
ExecuteEventArgs e = new ExecuteEventArgs();
e.StatementName = _statement.Id;
if (Execute != null)
{
Execute(this, e);
}
}
/// <summary>
/// ToString implementation.
/// </summary>
/// <returns>A string that describes the
MappedStatement</returns>
public override string ToString()
{
StringBuilder buffer = new StringBuilder();
buffer.Append("\tMappedStatement: " + this.Name +
"\n");
if (_statement.ParameterMap != null)
buffer.Append(_statement.ParameterMap.Id);
if (_statement.ResultMap != null)
buffer.Append(_statement.ResultMap.Id);
return buffer.ToString();
}
private ReaderAutoMapper _readerAutoMapper = null;
private void AutoMapReader( IDataReader reader,ref object
resultObject)
{
if (_readerAutoMapper == null)
{
lock (this)
{
if (_readerAutoMapper == null)
{
_readerAutoMapper = new
ReaderAutoMapper(_sqlMap.TypeHandlerFactory, reader, ref resultObject);
}
}
}
_readerAutoMapper.AutoMapReader( reader, ref
resultObject );
}
#endregion
private class ReaderAutoMapper
{
// private IList _mappings = new ArrayList();
private ResultMap _resultMap = new ResultMap();
/// <summary>
///
/// </summary>
/// <param name="reader"></param>
/// <param name="resultObject"></param>
/// <param name="typeHandlerFactory"></param>
public ReaderAutoMapper(TypeHandlerFactory
typeHandlerFactory, IDataReader reader,ref object resultObject)
{
try
{
// Get all PropertyInfo from the
resultObject properties
ReflectionInfo reflectionInfo =
ReflectionInfo.GetInstance(resultObject.GetType());
string[] propertiesName =
reflectionInfo.GetWriteablePropertyNames();
Hashtable propertyMap = new Hashtable();
for (int i = 0; i < propertiesName.Length;
i++)
{
propertyMap.Add(
propertiesName[i].ToUpper(), reflectionInfo.GetSetter(propertiesName[i])
);
}
// Get all column Name from the reader
// and build a resultMap from with the
help of the PropertyInfo[].
DataTable dataColumn =
reader.GetSchemaTable();
for (int i = 0; i < dataColumn.Rows.Count;
i++)
{
string columnName =
dataColumn.Rows[i][0].ToString();
PropertyInfo matchedPropertyInfo =
propertyMap[columnName.ToUpper()] as PropertyInfo;
ResultProperty property = new
ResultProperty();
property.ColumnName = columnName;
if (matchedPropertyInfo != null )
{
property.PropertyName =
matchedPropertyInfo.Name;
property.Initialize(typeHandlerFactory, matchedPropertyInfo );
_resultMap.AddResultPropery(property);
}
else if (resultObject is Hashtable)
{
property.PropertyName =
columnName;
_resultMap.AddResultPropery(property);
}
// Fix for IBATISNET-73 (JIRA-73)
from Ron Grabowski
if (property.PropertyName != null &&
property.PropertyName.Length > 0)
{
// Set TypeHandler
Type propertyType =
reflectionInfo.GetSetterType(property.PropertyName);
property.TypeHandler =
typeHandlerFactory.GetTypeHandler( propertyType );
}
else
{
if (_logger.IsDebugEnabled)
{
_logger.Debug("The
column [" + columnName + "] could not be auto mapped to a property on ["
+ resultObject.ToString() + "]");
}
}
}
}
catch (Exception e)
{
throw new DataMapperException("Error
automapping columns. Cause: " + e.Message, e);
}
}
/// <summary>
///
/// </summary>
/// <param name="reader"></param>
/// <param name="resultObject"></param>
public void AutoMapReader(IDataReader reader, ref
object resultObject)
{
foreach (string key in
_resultMap.ColumnsToPropertiesMap.Keys)
{
ResultProperty property = (ResultProperty)
_resultMap.ColumnsToPropertiesMap[key];
MappedStatement.SetValueOfProperty( ref
resultObject, property,
property.GetDataBaseValue( reader
));
}
}
}
}
}
Marco Rencelj
CAD iT - Information Technology
Via Torricelli 44/a - 37136 Verona
phone: +39(0)458211.111
direct: +39(0)458211.161
mobile: +3356008339
e-mail: rencelj@cad.it
www.cadit.it
Re: Error in using an ArrayList type as resultClass in IBatis for .net
Posted by Gilles Bayon <ib...@gmail.com>.
If you want to get an ArrayList, you don't need to specify the resultClass.
The listClass attribut is used for typed collection.
Sample from unit test
<select id="GetAllDocument"
resultMap="document">
select
*
from Documents
order by Document_Type, Document_Id
</select>
IList list = sqlMap.QueryForList("GetAllDocument", null);
On 11/11/05, Rencelj Marco <re...@cad.it> wrote:
>
> I had to get a list with a variable number of columns so I had to try
> ArrayList as resultClass (columns are unnamed).
>
> The ArrayList is populated with a correct number of rows but each row
> instance is an empty ArrayList.
>
> I fixed the problem in source code adding a code fragment in
> MappedStatement.cs as in included code.
>
> Anybody had the same problem? May be there is a release that include this
> fix …
>
> Thanks in advane
>
> Marco
>