#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.Xml; using System.Xml.Serialization; using IBatisNet.Common.Exceptions; using IBatisNet.Common.Utilities.Objects; using IBatisNet.Common.Utilities.TypesResolver; using IBatisNet.DataMapper.Configuration.Serializers; using IBatisNet.DataMapper.Scope; #endregion namespace IBatisNet.DataMapper.Configuration.ResultMapping { /// /// Summary description for ResultMap. /// [Serializable] [XmlRoot("resultMap", Namespace="http://ibatis.apache.org/mapping")] public class ResultMap { /// /// Token for xml path to result elements. /// private const string XML_RESULT = "result"; /// /// Token for xml path to discriminator elements. /// private const string XML_DISCRIMNATOR = "discriminator"; /// /// Token for xml path to subMap elements. /// private const string XML_SUBMAP = "subMap"; #region Fields [NonSerialized] private string _id = string.Empty; [NonSerialized] private string _className = string.Empty; [NonSerialized] private string _extendMap = string.Empty; [NonSerialized] private Type _class = null; //(columnName, property) [NonSerialized] private Hashtable _columnsToPropertiesMap = new Hashtable(); [NonSerialized] private Discriminator _discriminator = null; [NonSerialized] private string _sqlMapNameSpace = string.Empty; #endregion #region Properties /// /// The sqlMap namespace /// [XmlIgnore] public string SqlMapNameSpace { get { return _sqlMapNameSpace; } set { _sqlMapNameSpace = value; } } /// /// The discriminator used to choose the good SubMap /// [XmlIgnore] public Discriminator Discriminator { get { return _discriminator; } set { _discriminator = value; } } /// /// The collection of result properties. /// [XmlIgnore] public Hashtable ColumnsToPropertiesMap { get { return _columnsToPropertiesMap; } } /// /// Identifier used to identify the resultMap amongst the others. /// /// GetProduct [XmlAttribute("id")] public string Id { get { return _id; } set { if ((value == null) || (value.Length < 1)) throw new ArgumentNullException("The id attribute is mandatory in a ResultMap tag."); _id = value; } } /// /// Extend ResultMap attribute /// [XmlAttribute("extends")] public string ExtendMap { get { return _extendMap; } set { _extendMap = value; } } /// /// The output type class of the resultMap. /// [XmlIgnore] public Type Class { get { return _class; } } /// /// The output class name of the resultMap. /// /// Com.Site.Domain.Product [XmlAttribute("class")] public string ClassName { get { return _className; } set { if ((value == null) || (value.Length < 1)) throw new ArgumentNullException("The class attribute is mandatory in a ResultMap tag."); _className = value; } } #endregion #region Constructor (s) / Destructor /// /// Do not use direclty, only for serialization. /// public ResultMap() { } #endregion #region Methods #region Configuration /// /// Initialize the resultMap from an xmlNode.. /// /// public void Initialize( ConfigurationScope configScope ) { try { _class = configScope.SqlMapper.GetType(_className); // Load the child node GetChildNode(configScope); } catch(Exception e) { throw new ConfigurationException( string.Format("Could not configure ResultMap. ResultMap named \"{0}\" not found, failed. {1} Cause: {2}", _id, Environment.NewLine, e.Message) ); } } /// /// Get the result properties and the subMap properties. /// /// private void GetChildNode(ConfigurationScope configScope) { ResultProperty mapping = null; SubMap subMap = null; #region Load the Result Properties foreach ( XmlNode resultNode in configScope.NodeContext.SelectNodes( DomSqlMapBuilder.ApplyMappingNamespacePrefix(XML_RESULT), configScope.XmlNamespaceManager) ) { mapping = ResultPropertyDeSerializer.Deserialize( resultNode, configScope ); configScope.ErrorContext.MoreInfo = "initialize result property: "+mapping.PropertyName; mapping.Initialize( configScope, _class ); this.AddResultPropery( mapping ); } #endregion #region Load the Discriminator Property XmlNode discriminatorNode = configScope.NodeContext.SelectSingleNode(DomSqlMapBuilder.ApplyMappingNamespacePrefix(XML_DISCRIMNATOR), configScope.XmlNamespaceManager); if (discriminatorNode != null) { configScope.ErrorContext.MoreInfo = "initialize discriminator"; this.Discriminator = DiscriminatorDeSerializer.Deserialize(discriminatorNode, configScope); this.Discriminator.SetMapping( configScope, _class ); } #endregion #region Load the SubMap Properties if (configScope.NodeContext.SelectNodes(DomSqlMapBuilder.ApplyMappingNamespacePrefix(XML_SUBMAP), configScope.XmlNamespaceManager).Count>0 && this.Discriminator==null) { throw new ConfigurationException("The discriminator is null, but somehow a subMap was reached. This is a bug."); } foreach ( XmlNode resultNode in configScope.NodeContext.SelectNodes(DomSqlMapBuilder.ApplyMappingNamespacePrefix(XML_SUBMAP), configScope.XmlNamespaceManager) ) { configScope.ErrorContext.MoreInfo = "initialize subMap"; subMap = SubMapDeSerializer.Deserialize(resultNode, configScope); subMap.ResultMapName = this.SqlMapNameSpace + DomSqlMapBuilder.DOT + subMap.ResultMapName; this.Discriminator.Add( subMap ); } #endregion } #endregion /// /// Create an instance Of result. /// /// An object. public object CreateInstanceOfResult() { TypeCode typeCode = Type.GetTypeCode(_class); if (typeCode == TypeCode.Object) { return Activator.CreateInstance(_class); } else { return TypeAliasResolver.InstantiatePrimitiveType(typeCode); } } /// /// Add a ResultProperty to the list of ResultProperty. /// /// The property to add. public void AddResultPropery(ResultProperty property) { _columnsToPropertiesMap.Add( property.PropertyName, property ); } /// /// Set the value of an object property. /// /// The object to set the property. /// The result property to use. /// The database value to set. public void SetValueOfProperty( ref object target, ResultProperty property, object dataBaseValue ) { if (target is Hashtable) { ((Hashtable) target).Add(property.PropertyName, dataBaseValue); } else { if ( target.GetType() != _class ) { throw new ArgumentException( "Could not set value of type '"+ target.GetType() +"' in property '"+property.PropertyName+"' of type '"+_class+"'" ); } if ( property.PropertyInfo != null ) { ObjectProbe.SetPropertyValue(target, property.PropertyName, dataBaseValue); } else // Primitive type ('value') { target = dataBaseValue; } } } /// /// /// /// /// public ResultMap ResolveSubMap(IDataReader dataReader) { ResultMap subMap = this; if (_discriminator != null) { ResultProperty mapping = _discriminator.ResultProperty; object dataBaseValue = mapping.GetDataBaseValue( dataReader ); subMap = _discriminator.GetSubMap( dataBaseValue.ToString() ); if (subMap == null) { subMap = this; } else if (subMap != this) { subMap = subMap.ResolveSubMap(dataReader); } } return subMap; } #endregion } }