#region Apache Notice
/*****************************************************************************
* $Header: $
* $Revision: 587946 $
* $Date$
*
* 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
#region Using
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using Apache.Ibatis.DataMapper.Data;
using Apache.Ibatis.DataMapper.Model;
using Apache.Ibatis.DataMapper.Model.Cache;
using Apache.Ibatis.DataMapper.Model.Events;
using Apache.Ibatis.DataMapper.Model.Statements;
using Apache.Ibatis.DataMapper.Scope;
using Apache.Ibatis.DataMapper.Session;
#endregion
namespace Apache.Ibatis.DataMapper.MappedStatements
{
///
/// Acts as a decorator arounf an to add cache functionality
///
[DebuggerDisplay("MappedStatement: {mappedStatement.Id}")]
public sealed class CachingStatement : MappedStatementEventSupport, IMappedStatement
{
// Func
delegate T RequestRunner(RequestScope requestScope, ISession session, object parameter, CacheKey cacheKey, out bool cacheHit);
private readonly MappedStatement mappedStatement;
///
/// Event launch on Execute query
///
public event EventHandler Executed = delegate { };
///
/// Constructor
///
///
public CachingStatement(MappedStatement statement)
{
mappedStatement = statement;
}
#region IMappedStatement Members
///
/// The IPreparedCommand to use
///
public IPreparedCommand PreparedCommand
{
get { return mappedStatement.PreparedCommand; }
}
///
/// Name used to identify the MappedStatement amongst the others.
/// This the name of the SQL statment by default.
///
public string Id
{
get { return mappedStatement.Id; }
}
///
/// The SQL statment used by this MappedStatement
///
public IStatement Statement
{
get { return mappedStatement.Statement; }
}
///
/// The used by this MappedStatement
///
/// The model store.
public IModelStore ModelStore
{
get { return mappedStatement.ModelStore; }
}
///
/// Executes an SQL statement that returns DataTable.
///
/// The session used to execute the statement.
/// The object used to set the parameters in the SQL.
/// The object
public DataTable ExecuteQueryForDataTable(ISession session, object parameterObject)
{
RequestRunner requestRunner = delegate(RequestScope requestscope, ISession session2, object parameter, CacheKey cachekey, out bool cachehit)
{
cachehit = true;
DataTable dataTable = Statement.CacheModel[cachekey] as DataTable;
if (dataTable == null)
{
cachehit = false;
dataTable = mappedStatement.RunQueryForDataTable(requestscope, session, parameter);
Statement.CacheModel[cachekey] = dataTable;
}
return dataTable;
};
return CachingStatementExecute(PreSelectEventKey, PostSelectEventKey, session, parameterObject, "ExecuteQueryForDataTable", requestRunner);
}
///
/// 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 IDictionary ExecuteQueryForMap(ISession session, object parameterObject, string keyProperty, string valueProperty)
{
// this doesn't need to be in its own RunQueryForCachedMap method because the class is sealed and can't be called by anyone else
RequestRunner requestRunner = delegate(RequestScope requestscope, ISession session2, object parameter, CacheKey cachekey, out bool cachehit)
{
if (keyProperty != null)
{
cachekey.Update(keyProperty);
}
if (valueProperty != null)
{
cachekey.Update(valueProperty);
}
cachehit = true;
IDictionary map = Statement.CacheModel[cachekey] as IDictionary;
if (map == null)
{
cachehit = false;
map = mappedStatement.RunQueryForMap(requestscope, session, parameter, keyProperty, valueProperty, null);
Statement.CacheModel[cachekey] = map;
}
return map;
};
return CachingStatementExecute(PreSelectEventKey, PostSelectEventKey, session, parameterObject, "ExecuteQueryForMap", requestRunner);
}
#region ExecuteQueryForMap .NET 2.0
///
/// 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 IDictionary ExecuteQueryForDictionary(ISession session, object parameterObject, string keyProperty, string valueProperty)
{
// this doesn't need to be in its own RunQueryForCachedDictionary method because the class is sealed and can't be called by anyone else
RequestRunner> requestRunner = delegate(RequestScope requestScope, ISession session2, object parameter, CacheKey cacheKey, out bool cacheHit)
{
if (keyProperty != null)
{
cacheKey.Update(keyProperty);
}
if (valueProperty != null)
{
cacheKey.Update(valueProperty);
}
cacheHit = true;
IDictionary map = Statement.CacheModel[cacheKey] as IDictionary;
if (map == null)
{
cacheHit = false;
map = mappedStatement.RunQueryForDictionary(requestScope, session2, parameter, keyProperty, valueProperty, null);
Statement.CacheModel[cacheKey] = map;
}
return map;
};
return CachingStatementExecute(PreSelectEventKey, PostSelectEventKey, session, parameterObject, "ExecuteQueryForDictionary", requestRunner);
}
///
/// Runs a query with a custom object that gets a chance
/// to deal with each row as it is processed.
///
///
/// This method always bypasses the cache.
///
/// 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 IDictionary ExecuteQueryForDictionary(ISession session, object parameterObject, string keyProperty, string valueProperty, DictionaryRowDelegate rowDelegate)
{
return mappedStatement.ExecuteQueryForDictionary(session, parameterObject, keyProperty, valueProperty, rowDelegate);
}
#endregion
///
/// Execute an update statement. Also used for delete statement.
/// Return the number of row effected.
///
///
/// This method always bypasses the cache.
///
/// The session used to execute the statement.
/// The object used to set the parameters in the SQL.
/// The number of row effected.
public int ExecuteUpdate(ISession session, object parameterObject)
{
return mappedStatement.ExecuteUpdate(session, parameterObject);
}
///
/// Execute an insert statement. Fill the parameter object with
/// the ouput parameters if any, also could return the insert generated key
///
///
/// This method always bypasses the cache.
///
/// The session
/// The parameter object used to fill the statement.
/// Can return the insert generated key.
public object ExecuteInsert(ISession session, object parameterObject)
{
return mappedStatement.ExecuteInsert(session, parameterObject);
}
#region ExecuteQueryForList
///
/// Executes the SQL and and fill a strongly typed collection.
///
///
/// This method always bypasses the cache.
///
/// 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 void ExecuteQueryForList(ISession session, object parameterObject, IList resultObject)
{
mappedStatement.ExecuteQueryForList(session, parameterObject, resultObject);
}
///
/// Executes the SQL and retuns all rows selected.
///
/// The session used to execute the statement.
/// The object used to set the parameters in the SQL.
/// A List of result objects.
public IList ExecuteQueryForList(ISession session, object parameterObject)
{
// this doesn't need to be in its own RunQueryForCachedList method because the class is sealed and can't be called by anyone else
RequestRunner requestRunner = delegate(RequestScope requestScope, ISession session2, object parameter, CacheKey cacheKey, out bool cacheHit)
{
cacheHit = true;
IList list = Statement.CacheModel[cacheKey] as IList;
if (list == null)
{
cacheHit = false;
list = mappedStatement.RunQueryForList(requestScope, session, parameter, null, null);
Statement.CacheModel[cacheKey] = list;
}
return list;
};
return CachingStatementExecute(PreSelectEventKey, PostSelectEventKey, session, parameterObject, "ExecuteQueryForList", requestRunner);
}
#endregion
#region ExecuteQueryForList .NET 2.0
///
/// Executes the SQL and and fill a strongly typed collection.
///
///
/// This method always bypasses the cache.
///
/// 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 void ExecuteQueryForList(ISession session, object parameterObject, IList resultObject)
{
mappedStatement.ExecuteQueryForList(session, parameterObject, resultObject);
}
///
/// Executes the SQL and retuns all rows selected.
///
/// The session used to execute the statement.
/// The object used to set the parameters in the SQL.
/// A List of result objects.
public IList ExecuteQueryForList(ISession session, object parameterObject)
{
// this doesn't need to be in its own RunQueryForCachedList method because the class is sealed and can't be called by anyone else
RequestRunner> requestRunner = delegate(RequestScope requestScope, ISession session2, object parameter, CacheKey cacheKey, out bool cacheHit)
{
cacheHit = true;
IList list = Statement.CacheModel[cacheKey] as IList;
if (list == null)
{
cacheHit = false;
list = mappedStatement.RunQueryForList(requestScope, session, parameter, null, null);
Statement.CacheModel[cacheKey] = list;
}
return list;
};
return CachingStatementExecute(PreSelectEventKey, PostSelectEventKey, session, parameterObject, "ExecuteQueryForList", requestRunner);
}
#endregion
#region ExecuteQueryForObject
///
/// 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 object ExecuteQueryForObject(ISession session, object parameterObject, object resultObject)
{
// this doesn't need to be in its own RunQueryForCachedObject method because the class is sealed and can't be called by anyone else
RequestRunner