#region Apache Notice
/*****************************************************************************
* $Revision: 374175 $
* $LastChangedDate$
* $LastChangedBy$
*
* iBATIS.NET Data Mapper
* Copyright (C) 2008/2005 - The Apache Software Foundation
*
*
* 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
using System.Collections.Generic;
using System.Data;
using System.Text;
using Apache.Ibatis.DataMapper.MappedStatements.PropertyStrategy;
using Apache.Ibatis.DataMapper.Model.ResultMapping;
using Apache.Ibatis.DataMapper.Scope;
namespace Apache.Ibatis.DataMapper.MappedStatements.PropertStrategy
{
///
/// implementation when the resulMap have a keys attribute.
///
public sealed class CircularStrategy : BaseStrategy, IPropertyStrategy
{
private const string KEY_SEPARATOR = "\002";
private readonly IPropertyStrategy resultMapStrategy = null;
///
/// Initializes the class.
///
/// The result map strategy.
public CircularStrategy(IPropertyStrategy resultMapStrategy)
{
this.resultMapStrategy = resultMapStrategy;
}
#region IPropertyStrategy Members
///
/// Sets value of the specified on the target object.
///
/// The request.
/// The result map.
/// The ResultProperty.
/// The target.
/// The reader.
/// The keys
public void Set(RequestScope request, IResultMap resultMap, ResultProperty mapping, ref object target, IDataReader reader, object keys)
{
Get(request, resultMap, mapping, ref target, reader);
}
///
/// Gets the value of the specified that must be set on the target object.
///
/// The request.
/// The result map.
/// The mapping.
/// The target.
/// The reader.
///
public object Get(RequestScope request, IResultMap resultMap, ResultProperty mapping, ref object target, IDataReader reader)
{
object result = null;
IResultMap propertyRresultMap = mapping.NestedResultMap.ResolveSubMap(reader);
string circularKey = GetCircularKey(propertyRresultMap, reader);
// Gets the [key, result object] already build
IDictionary buildObjects = request.GetCirularKeys(propertyRresultMap);
if (buildObjects != null && buildObjects.ContainsKey(circularKey))
{
// circular key is already known, so get the existing result object
result = buildObjects[circularKey];
}
else if (circularKey == null || buildObjects == null || !buildObjects.ContainsKey(circularKey))
{
// circular key is NOT known, so create a new result object.
result = resultMapStrategy.Get(request, resultMap, mapping, ref target, reader);
if (buildObjects == null)
{
buildObjects = new Dictionary();
request.SetCirularKeys(propertyRresultMap, buildObjects);
}
buildObjects[circularKey] = result;
}
return result;
}
#endregion
///
/// Gets the circular key.
///
/// The result map.
/// The reader.
///
private static string GetCircularKey(IResultMap resultMap, IDataReader reader)
{
if (resultMap.KeysProperties.Count > 0)
{
StringBuilder keyBuffer = new StringBuilder();
for (int i = 0; i < resultMap.KeysProperties.Count; i++)
{
ResultProperty resultProperty = resultMap.KeysProperties[i];
keyBuffer.Append(resultProperty.GetDataBaseValue(reader));
keyBuffer.Append('-');
}
if (keyBuffer.Length < 1)
{
// we should never go here
return null;
}
// separator value not likely to appear in a database
keyBuffer.Append(KEY_SEPARATOR);
return keyBuffer.ToString();
}
// we should never go here
return null;
}
}
}