#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
}
}