#region Apache Notice
/*****************************************************************************
* $Header: $
* $Revision: $
* $Date: $
*
* iBATIS.NET Data Mapper
* Copyright (C) 2004 - Gilles Bayon
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
********************************************************************************/
#endregion
#region Imports
using System;
using System.Collections;
using System.Data;
using System.Reflection;
using System.Text;
using IBatisNet.Common;
using IBatisNet.Common.Logging;
using IBatisNet.Common.Utilities;
using IBatisNet.Common.Utilities.Objects;
using IBatisNet.DataMapper.Commands;
using IBatisNet.DataMapper.Configuration.ParameterMapping;
using IBatisNet.DataMapper.Configuration.ResultMapping;
using IBatisNet.DataMapper.Configuration.Statements;
using IBatisNet.DataMapper.Exceptions;
using IBatisNet.DataMapper.Scope;
using IBatisNet.DataMapper.TypeHandlers;
#endregion
namespace IBatisNet.DataMapper.MappedStatements
{
///
/// Summary description for MappedStatement.
///
public class MappedStatement : IMappedStatement
{
///
/// Event launch on exceute query
///
public event ExecuteEventHandler Execute;
///
/// Enumeration of the ExecuteQuery method.
///
private enum ExecuteMethod : int
{
ExecuteQueryForObject =0,
ExecuteQueryForIList,
ExecuteQueryForArrayList,
ExecuteQueryForStrongTypedIList
}
///
/// All data tor retrieve 'select' result property
///
///
/// As ADO.NET allows to open DataReader per connection at once, we keep
/// all th data to make the open the 'whish' DataReader after having closed the current.
///
private class PostBindind
{
#region Fields
private IMappedStatement _statement = null;
private ResultProperty _property = null;
private object _target = null;
private object _keys = null;
private ExecuteMethod _method = ExecuteMethod.ExecuteQueryForIList;
#endregion
#region Properties
///
///
///
public IMappedStatement Statement
{
set { _statement = value; }
get { return _statement; }
}
///
///
///
public ResultProperty ResultProperty
{
set { _property = value; }
get { return _property; }
}
///
///
///
public object Target
{
set { _target = value; }
get { return _target; }
}
///
///
///
public object Keys
{
set { _keys = value; }
get { return _keys; }
}
///
///
///
public ExecuteMethod Method
{
set { _method = value; }
get { return _method; }
}
#endregion
}
#region Fields
// Magic number used to set the the maximum number of rows returned to 'all'.
internal const int NO_MAXIMUM_RESULTS = -1;
// Magic number used to set the the number of rows skipped to 'none'.
internal const int NO_SKIPPED_RESULTS = -1;
private static readonly ILog _logger = LogManager.GetLogger( MethodBase.GetCurrentMethod().DeclaringType );
private IStatement _statement = null;
private SqlMapper _sqlMap = null;
private IPreparedCommand _preparedCommand = null;
#endregion
#region Properties
///
/// The IPreparedCommand to use
///
public IPreparedCommand PreparedCommand
{
get { return _preparedCommand; }
}
///
/// Name used to identify the MappedStatement amongst the others.
/// This the name of the SQL statement by default.
///
public string Id
{
get { return _statement.Id; }
}
///
/// The SQL statment used by this MappedStatement
///
public IStatement Statement
{
get { return _statement; }
}
///
/// The SqlMap used by this MappedStatement
///
public SqlMapper SqlMap
{
get { return _sqlMap; }
}
#endregion
#region Constructor (s) / Destructor
///
/// Constructor
///
/// An SqlMap
/// An SQL statement
internal MappedStatement( SqlMapper sqlMap, IStatement statement )
{
_sqlMap = sqlMap;
_statement = statement;
_preparedCommand = PreparedCommandFactory.GetPreparedCommand( false );
}
#endregion
#region Methods
///
///
///
///
///
///
///
private bool FillObjectWithReaderAndResultMap(RequestScope request,IDataReader reader,
ResultMap resultMap, object resultObject)
{
bool dataFound = false;
// For each Property in the ResultMap, set the property in the object
foreach(DictionaryEntry entry in resultMap.ColumnsToPropertiesMap)
{
request.IsRowDataFound = false;
ResultProperty property = (ResultProperty)entry.Value;
SetObjectProperty(request, resultMap, property, ref resultObject, reader);
dataFound = dataFound || request.IsRowDataFound;
}
request.IsRowDataFound = dataFound;
return dataFound;
}
///
///
///
///
///
///
///
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 IDictionary)
{
for (int i = 0; i < reader.FieldCount; i++)
{
ResultProperty property = new ResultProperty();
property.PropertyName = "value";
property.ColumnIndex = i;
property.TypeHandler = _sqlMap.TypeHandlerFactory.GetTypeHandler(reader.GetFieldType(i));
((IDictionary) outObject).Add(
reader.GetName(i),
property.GetDataBaseValue(reader));
}
}
else if (outObject is IList)
{
for (int i = 0; i < reader.FieldCount; i++)
{
ResultProperty property = new ResultProperty();
property.PropertyName = "value";
property.ColumnIndex = i;
property.TypeHandler = _sqlMap.TypeHandlerFactory.GetTypeHandler(reader.GetFieldType(i));
((IList) outObject).Add(property.GetDataBaseValue(reader));
}
}
else
{
AutoMapReader( reader, ref outObject);
}
}
else
{
if (reader.FieldCount == 1)
{
ResultProperty property = new ResultProperty();
property.PropertyName = "value";
property.ColumnIndex = 0;
property.TypeHandler = _sqlMap.TypeHandlerFactory.GetTypeHandler(reader.GetFieldType(0));
outObject = property.GetDataBaseValue(reader);
}
else if (reader.FieldCount > 1)
{
object[] newOutObject = new object[reader.FieldCount];
for (int i = 0; i < reader.FieldCount; i++)
{
ResultProperty property = new ResultProperty();
property.PropertyName = "value";
property.ColumnIndex = i;
property.TypeHandler = _sqlMap.TypeHandlerFactory.GetTypeHandler(reader.GetFieldType(i));
newOutObject[i] = property.GetDataBaseValue(reader);
}
outObject = newOutObject;
}
else
{
// do nothing if 0 fields
}
}
}
return outObject;
}
///
/// 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...
///
///
/// The current session.
/// The result object.
/// The command sql.
private void RetrieveOutputParameters(RequestScope request, IDalSession session, IDbCommand command, object result)
{
if (request.ParameterMap != null)
{
for(int i=0; i
/// Executes an SQL statement that returns a single row as an Object.
///
/// The session used to execute the statement.
/// The object used to set the parameters in the SQL.
/// The object
public virtual object ExecuteQueryForObject( IDalSession session, object parameterObject )
{
return ExecuteQueryForObject(session, parameterObject, null);
}
///
/// Executes an SQL statement that returns a single row as an Object of the type of
/// the resultObject passed in as a parameter.
///
/// The session used to execute the statement.
/// The object used to set the parameters in the SQL.
/// The result object.
/// The object
public virtual object ExecuteQueryForObject(IDalSession session, object parameterObject, object resultObject )
{
object obj = null;
RequestScope request = _statement.Sql.GetRequestScope(parameterObject, session);;
_preparedCommand.Create( request, session, this.Statement, parameterObject );
obj = RunQueryForObject(request, session, parameterObject, resultObject);
return obj;
}
///
/// Executes an SQL statement that returns a single row as an Object of the type of
/// the resultObject passed in as a parameter.
///
/// The request scope.
/// The session used to execute the statement.
/// The object used to set the parameters in the SQL.
/// The result object.
/// The object
internal object RunQueryForObject(RequestScope request, IDalSession session, object parameterObject, object resultObject )
{
object result = resultObject;
using ( IDbCommand command = request.IDbCommand )
{
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);
}
RaiseExecuteEvent();
return result;
}
#endregion
#region ExecuteQueryForList
///
/// Runs a query with a custom object that gets a chance
/// to deal with each row as it is processed.
///
/// The session used to execute the statement.
/// The object used to set the parameters in the SQL.
///
public virtual IList ExecuteQueryForRowDelegate( IDalSession session, object parameterObject, SqlMapper.RowDelegate rowDelegate )
{
RequestScope request = _statement.Sql.GetRequestScope(parameterObject, session);;
_preparedCommand.Create( request, session, this.Statement, parameterObject );
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);
}
///
/// Runs a query with a custom object that gets a chance
/// to deal with each row as it is processed.
///
/// The session used to execute the statement
/// The object used to set the parameters in the SQL.
/// The property of the result object to be used as the key.
/// The property of the result object to be used as the value (or null)
///
/// A hashtable of object containing the rows keyed by keyProperty.
///If a transaction is not in progress, or the database throws an exception.
public virtual IDictionary ExecuteQueryForMapWithRowDelegate( IDalSession session, object parameterObject, string keyProperty, string valueProperty, SqlMapper.DictionaryRowDelegate rowDelegate )
{
RequestScope request = _statement.Sql.GetRequestScope(parameterObject, session);;
if (rowDelegate == null)
{
throw new DataMapperException("A null DictionaryRowDelegate was passed to QueryForMapWithRowDelegate.");
}
_preparedCommand.Create(request, session, this.Statement, parameterObject);
return RunQueryForMap(request, session, parameterObject, keyProperty, valueProperty, rowDelegate);
}
///
/// Executes the SQL and retuns all rows selected. This is exactly the same as
/// calling ExecuteQueryForList(session, parameterObject, NO_SKIPPED_RESULTS, NO_MAXIMUM_RESULTS).
///
/// The session used to execute the statement.
/// The object used to set the parameters in the SQL.
/// A List of result objects.
public virtual IList ExecuteQueryForList( IDalSession session, object parameterObject )
{
return ExecuteQueryForList( session, parameterObject, NO_SKIPPED_RESULTS, NO_MAXIMUM_RESULTS);
}
///
/// Executes the SQL and retuns a subset of the rows selected.
///
/// The session used to execute the statement.
/// The object used to set the parameters in the SQL.
/// The number of rows to skip over.
/// The maximum number of rows to return.
/// A List of result objects.
public virtual IList ExecuteQueryForList( IDalSession session, object parameterObject, int skipResults, int maxResults )
{
IList list = null;
RequestScope request = _statement.Sql.GetRequestScope(parameterObject, session);;
_preparedCommand.Create( request, session, this.Statement, parameterObject );
list = RunQueryForList(request, session, parameterObject, skipResults, maxResults, null);
return list;
}
///
/// Executes the SQL and retuns a List of result objects.
///
/// The request scope.
/// The session used to execute the statement.
/// The object used to set the parameters in the SQL.
/// The number of rows to skip over.
/// The maximum number of rows to return.
///
/// A List of result objects.
internal IList RunQueryForList(RequestScope request, IDalSession session, object parameterObject, int skipResults, int maxResults, SqlMapper.RowDelegate rowDelegate)
{
IList list = null;
using ( IDbCommand command = request.IDbCommand )
{
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, parameterObject, list);
n++;
}
}
}
ExecutePostSelect( session, request);
RetrieveOutputParameters(request, session, command, parameterObject);
}
return list;
}
///
/// Executes the SQL and and fill a strongly typed collection.
///
/// The session used to execute the statement.
/// The object used to set the parameters in the SQL.
/// A strongly typed collection of result objects.
public virtual void ExecuteQueryForList(IDalSession session, object parameterObject, IList resultObject )
{
RequestScope request = _statement.Sql.GetRequestScope(parameterObject, session);;
_preparedCommand.Create( request, session, this.Statement, parameterObject );
using ( IDbCommand command = request.IDbCommand )
{
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
///
/// Execute an update statement. Also used for delete statement.
/// Return the number of row effected.
///
/// The session used to execute the statement.
/// The object used to set the parameters in the SQL.
/// The number of row effected.
public virtual int ExecuteUpdate(IDalSession session, object parameterObject )
{
int rows = 0; // the number of rows affected
RequestScope request = _statement.Sql.GetRequestScope(parameterObject, session);;
_preparedCommand.Create( request, session, this.Statement, parameterObject );
using ( IDbCommand command = request.IDbCommand )
{
rows = command.ExecuteNonQuery();
ExecutePostSelect( session, request);
RetrieveOutputParameters(request, session, command, parameterObject);
}
RaiseExecuteEvent();
return rows;
}
///
/// Execute an insert statement. Fill the parameter object with
/// the ouput parameters if any, also could return the insert generated key
///
/// The session
/// The parameter object used to fill the statement.
/// Can return the insert generated key.
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)
{
IMappedStatement mappedStatement = _sqlMap.GetMappedStatement( selectKeyStatement.Id );
generatedKey = mappedStatement.ExecuteQueryForObject(session, parameterObject);
ObjectProbe.SetPropertyValue(parameterObject, selectKeyStatement.PropertyName, generatedKey);
}
_preparedCommand.Create( request, session, this.Statement, parameterObject );
using ( IDbCommand command = request.IDbCommand)
{
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)
{
IMappedStatement 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
///
/// 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.
///
/// The session used to execute the statement
/// The object used to set the parameters in the SQL.
/// The property of the result object to be used as the key.
/// The property of the result object to be used as the value (or null)
/// A hashtable of object containing the rows keyed by keyProperty.
///If a transaction is not in progress, or the database throws an exception.
public virtual IDictionary ExecuteQueryForMap( IDalSession session, object parameterObject, string keyProperty, string valueProperty )
{
IDictionary map = new Hashtable();
RequestScope request = _statement.Sql.GetRequestScope(parameterObject, session);
_preparedCommand.Create(request, session, this.Statement, parameterObject);
map = RunQueryForMap(request, session, parameterObject, keyProperty, valueProperty, null );
return map;
}
///
/// 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.
///
/// The request scope.
/// The session used to execute the statement
/// The object used to set the parameters in the SQL.
/// The property of the result object to be used as the key.
/// The property of the result object to be used as the value (or null)
///
/// A hashtable of object containing the rows keyed by keyProperty.
///If a transaction is not in progress, or the database throws an exception.
internal IDictionary RunQueryForMap( RequestScope request,
IDalSession session,
object parameterObject,
string keyProperty,
string valueProperty,
SqlMapper.DictionaryRowDelegate rowDelegate )
{
IDictionary map = new Hashtable();
using (IDbCommand command = request.IDbCommand)
{
using (IDataReader reader = command.ExecuteReader())
{
if (rowDelegate == 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);
}
rowDelegate(key, value, parameterObject, map);
}
}
}
}
return map;
}
#endregion
///
/// Process 'select' result properties
///
///
///
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.PropertyType);
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
///
///
///
///
///
///
///
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 || mapping.TypeHandler is UnknownTypeHandler) // Find the TypeHandler
{
lock(mapping)
{
if (mapping.TypeHandler == null || mapping.TypeHandler is UnknownTypeHandler)
{
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 );
request.IsRowDataFound = request.IsRowDataFound || (dataBaseValue != null);
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();
if (FillObjectWithReaderAndResultMap(request, reader, mapping.NestedResultMap, obj) == false)
{
obj = null;
}
MappedStatement.SetValueOfProperty( ref target, mapping, obj );
}
else //'select' ResultProperty
{
// Get the select statement
IMappedStatement 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 == 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(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)
{
ObjectProbe.SetPropertyValue( target, property.PropertyName, null);
// if (property.PropertyInfo != null)
// {
// property.PropertyInfo.SetValue( target, null, null );
// }
// else
// {
// ObjectProbe.SetPropertyValue( target, property.PropertyName, null);
// }
}
else
{
ObjectProbe.SetPropertyValue(target, property.PropertyName, dataBaseValue);
// if (property.PropertyInfo != null)
// {
// property.PropertyInfo.SetValue( target, dataBaseValue, null );
// }
// else
// {
// ObjectProbe.SetPropertyValue( target, property.PropertyName, dataBaseValue);
// }
}
}
}
}
///
/// Raise an event ExecuteEventArgs
/// (Used when a query is executed)
///
private void RaiseExecuteEvent()
{
ExecuteEventArgs e = new ExecuteEventArgs();
e.StatementName = _statement.Id;
if (Execute != null)
{
Execute(this, e);
}
}
///
/// ToString implementation.
///
/// A string that describes the MappedStatement
public override string ToString()
{
StringBuilder buffer = new StringBuilder();
buffer.Append("\tMappedStatement: " + this.Id);
buffer.Append(Environment.NewLine);
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 (_statement.RemapResults)
{
ReaderAutoMapper readerAutoMapper = new ReaderAutoMapper(_sqlMap.TypeHandlerFactory, reader, ref resultObject);
readerAutoMapper.AutoMapReader( reader, ref resultObject );
_logger.Debug("The RemapResults");
}
else
{
if (_readerAutoMapper == null)
{
lock (this)
{
if (_readerAutoMapper == null)
{
_readerAutoMapper = new ReaderAutoMapper(_sqlMap.TypeHandlerFactory, reader, ref resultObject);
}
}
}
_logger.Debug("The AutoMapReader");
_readerAutoMapper.AutoMapReader( reader, ref resultObject );
}
}
#endregion
private class ReaderAutoMapper
{
private ResultMap _resultMap = new ResultMap();
///
///
///
///
///
///
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;
property.ColumnIndex = i;
if (resultObject is Hashtable)
{
property.PropertyName = columnName;
_resultMap.AddResultPropery(property);
}
Type propertyType = null;
if (matchedPropertyInfo == null )
{
try
{
propertyType = ObjectProbe.GetPropertyTypeForSetter(resultObject, columnName);
}
catch
{
_logger.Error("The column [" + columnName + "] could not be auto mapped to a property on [" + resultObject.ToString() + "]");
}
}
else
{
propertyType = reflectionInfo.GetSetterType(matchedPropertyInfo.Name);
}
if(propertyType != null || matchedPropertyInfo != null)
{
property.PropertyName = (matchedPropertyInfo != null ? matchedPropertyInfo.Name : columnName );
if (matchedPropertyInfo != null)
{
property.Initialize(typeHandlerFactory, matchedPropertyInfo );
}
else
{
property.TypeHandler = typeHandlerFactory.GetTypeHandler(propertyType);
}
_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);
}
}
///
///
///
///
///
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 ));
}
}
}
}
}