#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.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 Name { 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(sqlMap.UseEmbedStatementParams); } #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 Hashtable) { for (int i = 0; i < reader.FieldCount; i++) { string columnName = reader.GetName(i); ((Hashtable) outObject).Add(columnName, reader.GetValue(i)); } } else { AutoMapReader( reader, ref outObject); } } } 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);; 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 = _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); } 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);; 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."); } 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);; 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 = _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, 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);; //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 /// /// 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);; //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; } /// /// 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); } 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) { 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);; 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 = _preparedCommand.Create(request, session, this.Statement, parameterObject)) { 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.Name); 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 )); } } } } }