Mercurial > pub > bltoolkit
view Source/Data/DbManager.cs @ 4:f757da6161a1
!bug 100 + 2h fixed gregression
author | cin |
---|---|
date | Sun, 24 Aug 2014 17:57:42 +0400 |
parents | f990fcb411a9 |
children |
line wrap: on
line source
using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Data.Common; using System.Data.SqlTypes; using System.Diagnostics; using System.Text; #region ReSharper disable // ReSharper disable UnusedParameter.Local #pragma warning disable 1589 #endregion namespace BLToolkit.Data { using Common; using DataProvider; using Mapping; using Properties; using Reflection; using Sql; /// <summary> /// The <b>DbManager</b> is a primary class of the <see cref="BLToolkit.Data"/> namespace /// that can be used to execute commands of different database providers. /// </summary> /// <remarks> /// When the <b>DbManager</b> goes out of scope, it does not close the internal connection object. /// Therefore, you must explicitly close the connection by calling <see cref="Close"/> or /// <see cref="Dispose(bool)"/>. Also, you can use the C# <b>using</b> statement. /// </remarks> /// <include file="Examples.xml" path='examples/db[@name="DbManager"]/*' /> [DesignerCategory(@"Code")] public partial class DbManager: Component { #region Init public DbManager(DataProviderBase dataProvider, string connectionString) { if (dataProvider == null) throw new ArgumentNullException("dataProvider"); if (connectionString == null) throw new ArgumentNullException("connectionString"); _dataProvider = dataProvider; _connection = dataProvider.CreateConnectionObject(); _connection.ConnectionString = connectionString; _dataProvider.InitDbManager(this); } public DbManager(DataProviderBase dataProvider, IDbConnection connection) { if (dataProvider == null) throw new ArgumentNullException("dataProvider"); if (connection == null) throw new ArgumentNullException("connection"); _dataProvider = dataProvider; _connection = connection; _dataProvider.InitDbManager(this); } public DbManager(DataProviderBase dataProvider, IDbTransaction transaction) { if (dataProvider == null) throw new ArgumentNullException("dataProvider"); if (transaction == null) throw new ArgumentNullException("transaction"); _dataProvider = dataProvider; _connection = transaction.Connection; _transaction = transaction; _closeTransaction = false; _dataProvider.InitDbManager(this); } DbManager(int n) { } public virtual DbManager Clone() { var clone = new DbManager(0) { _configurationString = _configurationString, _dataProvider = _dataProvider, _mappingSchema = _mappingSchema }; if (_connection != null) clone._connection = CloneConnection(); return clone; } public string LastQuery; #endregion #region Public Properties private MappingSchema _mappingSchema = Map.DefaultSchema; /// <summary> /// Gets the <see cref="BLToolkit.Mapping.MappingSchema"/> /// used by this instance of the <see cref="DbManager"/>. /// </summary> /// <value> /// A mapping schema. /// </value> public MappingSchema MappingSchema { [DebuggerStepThrough] get { return _mappingSchema; } set { _mappingSchema = value ?? Map.DefaultSchema; } } private DataProviderBase _dataProvider; /// <summary> /// Gets the <see cref="BLToolkit.Data.DataProvider.DataProviderBase"/> /// used by this instance of the <see cref="DbManager"/>. /// </summary> /// <value> /// A data provider. /// </value> /// <include file="Examples.xml" path='examples/db[@name="DataProvider"]/*' /> public DataProviderBase DataProvider { [DebuggerStepThrough] get { return _dataProvider; } protected set { _dataProvider = value; } } private static TraceSwitch _traceSwitch; public static TraceSwitch TraceSwitch { get { return _traceSwitch ?? (_traceSwitch = new TraceSwitch("DbManager", "DbManager trace switch", #if DEBUG "Warning" #else "Off" #endif )); } set { _traceSwitch = value; } } public static void TurnTraceSwitchOn() { TraceSwitch = new TraceSwitch("DbManager", "DbManager trace switch", "Info"); } public static Action<string,string> WriteTraceLine = (message, displayName) => Debug.WriteLine(message, displayName); private bool _canRaiseEvents = true; public new bool CanRaiseEvents { get { return _canRaiseEvents && base.CanRaiseEvents; } set { _canRaiseEvents = value; } } /// <summary> /// Use plain text query instead of using command parameters /// </summary> public bool UseQueryText { get; set; } #endregion #region Connection private bool _closeConnection; private IDbConnection _connection; /// <summary> /// Gets or sets the <see cref="IDbConnection"/> used by this instance of the <see cref="DbManager"/>. /// </summary> /// <value> /// The connection to the data source. /// </value> /// <remarks> /// Then you set a connection object, it has to match the data source type. /// </remarks> /// <exception cref="DataException"> /// A connection does not match the data source type. /// </exception> /// <include file="Examples.xml" path='examples/db[@name="Connection"]/*' /> public IDbConnection Connection { [DebuggerStepThrough] get { if (_connection.State == ConnectionState.Closed) OpenConnection(); return _connection; } set { if (value == null) throw new ArgumentNullException("value"); if (value.GetType() != _dataProvider.ConnectionType) InitDataProvider(value); _connection = value; _closeConnection = false; } } [Obsolete] protected virtual string GetConnectionString(IDbConnection connection) { return connection.ConnectionString; } private void OpenConnection() { ExecuteOperation(OperationType.OpenConnection, _connection.Open); _closeConnection = true; } /// <summary> /// Closes the connection to the database. /// </summary> /// <remarks> /// The <b>Close</b> method rolls back any pending transactions /// and then closes the connection. /// </remarks> /// <include file="Examples.xml" path='examples/db[@name="Close()"]/*' /> /// <seealso cref="Dispose(bool)"/> public void Close() { if (OnClosing != null) OnClosing(this, EventArgs.Empty); if (_selectCommand != null) { _selectCommand.Dispose(); _selectCommand = null; } if (_insertCommand != null) { _insertCommand.Dispose(); _insertCommand = null; } if (_updateCommand != null) { _updateCommand.Dispose(); _updateCommand = null; } if (_deleteCommand != null) { _deleteCommand.Dispose(); _deleteCommand = null; } if (_transaction != null && _closeTransaction) { ExecuteOperation(OperationType.DisposeTransaction, _transaction.Dispose); _transaction = null; } if (_connection != null && _closeConnection) { ExecuteOperation(OperationType.CloseConnection, _connection.Dispose); _connection = null; } if (OnClosed != null) OnClosed(this, EventArgs.Empty); } private bool? _isMarsEnabled; public bool IsMarsEnabled { get { if (_isMarsEnabled == null) _isMarsEnabled = DataProvider.IsMarsEnabled(Connection); return _isMarsEnabled.Value; } set { _isMarsEnabled = value; } } #endregion #region Transactions private bool _closeTransaction = true; private IDbTransaction _transaction; /// <summary> /// Gets the <see cref="IDbTransaction"/> used by this instance of the <see cref="DbManager"/>. /// </summary> /// <value> /// The <see cref="IDbTransaction"/>. The default value is a null reference. /// </value> /// <remarks> /// You have to call the <see cref="BeginTransaction()"/> method to begin a transaction. /// </remarks> /// <include file="Examples.xml" path='examples/db[@name="Transaction"]/*' /> /// <seealso cref="BeginTransaction()"/> public IDbTransaction Transaction { [DebuggerStepThrough] get { return _transaction; } } /// <summary> /// Begins a database transaction. /// </summary> /// <remarks> /// Once the transaction has completed, you must explicitly commit or roll back the transaction /// by using the <see cref="System.Data.IDbTransaction.Commit"/>> or /// <see cref="System.Data.IDbTransaction.Rollback"/> methods. /// </remarks> /// <include file="Examples.xml" path='examples/db[@name="BeginTransaction()"]/*' /> /// <returns>This instance of the <see cref="DbManager"/>.</returns> /// <seealso cref="Transaction"/> public virtual DbManager BeginTransaction() { return BeginTransaction(IsolationLevel.ReadCommitted); } /// <summary> /// Begins a database transaction with the specified <see cref="IsolationLevel"/> value. /// </summary> /// <remarks> /// Once the transaction has completed, you must explicitly commit or roll back the transaction /// by using the <see cref="System.Data.IDbTransaction.Commit"/> or /// <see cref="System.Data.IDbTransaction.Rollback"/> methods. /// </remarks> /// <include file="Examples.xml" path='examples/db[@name="BeginTransaction(IsolationLevel)"]/*' /> /// <param name="il">One of the <see cref="IsolationLevel"/> values.</param> /// <returns>This instance of the <see cref="DbManager"/>.</returns> public virtual DbManager BeginTransaction(IsolationLevel il) { // If transaction is open, we dispose it, it will rollback all changes. // if (_transaction != null) { ExecuteOperation(OperationType.DisposeTransaction, _transaction.Dispose); } // Create new transaction object. // _transaction = ExecuteOperation( OperationType.BeginTransaction, () => Connection.BeginTransaction(il)); _closeTransaction = true; // If the active command exists. // if (_selectCommand != null) _selectCommand.Transaction = _transaction; if (_insertCommand != null) _insertCommand.Transaction = _transaction; if (_updateCommand != null) _updateCommand.Transaction = _transaction; if (_deleteCommand != null) _deleteCommand.Transaction = _transaction; return this; } /// <summary> /// Commits the database transaction. /// </summary> /// <returns>This instance of the <see cref="DbManager"/>.</returns> public virtual DbManager CommitTransaction() { if (_transaction != null) { ExecuteOperation(OperationType.CommitTransaction, _transaction.Commit); if (_closeTransaction) { ExecuteOperation(OperationType.DisposeTransaction, _transaction.Dispose); _transaction = null; } } return this; } /// <summary> /// Rolls back a transaction from a pending state. /// </summary> /// <returns>This instance of the <see cref="DbManager"/>.</returns> public virtual DbManager RollbackTransaction() { if (_transaction != null) { ExecuteOperation(OperationType.RollbackTransaction, _transaction.Rollback); if (_closeTransaction) { ExecuteOperation(OperationType.DisposeTransaction, _transaction.Dispose); _transaction = null; } } return this; } #endregion #region Commands private IDbCommand _selectCommand; /// <summary> /// Gets the <see cref="IDbCommand"/> used by this instance of the <see cref="DbManager"/>. /// </summary> /// <value> /// A <see cref="IDbCommand"/> used during executing query. /// </value> /// <remarks> /// The <b>Command</b> can be used to access command parameters. /// </remarks> /// <include file="Examples.xml" path='examples/db[@name="Command"]/*' /> public IDbCommand Command { [DebuggerStepThrough] get { return SelectCommand; } } /// <summary> /// Gets the select <see cref="IDbCommand"/> used by this instance of the <see cref="DbManager"/>. /// </summary> /// <value> /// A <see cref="IDbCommand"/> used during executing query. /// </value> /// <remarks> /// The <b>SelectCommand</b> can be used to access select command parameters. /// </remarks> /// <include file="Examples.xml" path='examples/db[@name="Command"]/*' /> public IDbCommand SelectCommand { [DebuggerStepThrough] get { return _selectCommand = OnInitCommand(_selectCommand); } } private IDbCommand _insertCommand; /// <summary> /// Gets the insert <see cref="IDbCommand"/> used by this instance of the <see cref="DbManager"/>. /// </summary> /// <value> /// A <see cref="IDbCommand"/> used during executing query. /// </value> /// <remarks> /// The <b>InsertCommand</b> can be used to access insert command parameters. /// </remarks> /// <include file="Examples.xml" path='examples/db[@name="Command"]/*' /> public IDbCommand InsertCommand { [DebuggerStepThrough] get { return _insertCommand = OnInitCommand(_insertCommand); } } private IDbCommand _updateCommand; /// <summary> /// Gets the update <see cref="IDbCommand"/> used by this instance of the <see cref="DbManager"/>. /// </summary> /// <value> /// A <see cref="IDbCommand"/> used during executing query. /// </value> /// <remarks> /// The <b>UpdateCommand</b> can be used to access update command parameters. /// </remarks> /// <include file="Examples.xml" path='examples/db[@name="Command"]/*' /> public IDbCommand UpdateCommand { [DebuggerStepThrough] get { return _updateCommand = OnInitCommand(_updateCommand); } } private IDbCommand _deleteCommand; /// <summary> /// Gets the delete <see cref="IDbCommand"/> used by this instance of the <see cref="DbManager"/>. /// </summary> /// <value> /// A <see cref="IDbCommand"/> used during executing query. /// </value> /// <remarks> /// The <b>DeleteCommand</b> can be used to access delete command parameters. /// </remarks> /// <include file="Examples.xml" path='examples/db[@name="Command"]/*' /> public IDbCommand DeleteCommand { [DebuggerStepThrough] get { return _deleteCommand = OnInitCommand(_deleteCommand); } } /// <summary> /// Initializes a command and raises the <see cref="InitCommand"/> event. /// </summary> protected virtual IDbCommand OnInitCommand(IDbCommand command) { if (command == null) { // Create a command object. // command = _dataProvider.CreateCommandObject(Connection); // If an active transaction exists. // if (Transaction != null) { command.Transaction = Transaction; } } if (CanRaiseEvents) { var handler = (InitCommandEventHandler)Events[_eventInitCommand]; if (handler != null) handler(this, new InitCommandEventArgs(command)); } return command; } /// <summary> /// Helper function. Creates the command object and sets command type and command text. /// </summary> /// <param name="commandAction">Command action.</param> /// <param name="commandType">The <see cref="System.Data.CommandType"/> /// (stored procedure, text, etc.)</param> /// <param name="sql">The SQL statement.</param> /// <returns>The command object.</returns> private IDbCommand GetCommand(CommandAction commandAction, CommandType commandType, string sql) { var command = GetCommand(commandAction, commandType); command.Parameters.Clear(); command.CommandType = commandType; command.CommandText = sql; return command; } #endregion #region Events public event EventHandler OnClosing; public event EventHandler OnClosed; private static readonly object _eventBeforeOperation = new object(); /// <summary> /// Occurs when a server-side operation is about to start. /// </summary> public event OperationTypeEventHandler BeforeOperation { add { Events.AddHandler (_eventBeforeOperation, value); } remove { Events.RemoveHandler(_eventBeforeOperation, value); } } private static readonly object _eventAfterOperation = new object(); /// <summary> /// Occurs when a server-side operation is complete. /// </summary> public event OperationTypeEventHandler AfterOperation { add { Events.AddHandler (_eventAfterOperation, value); } remove { Events.RemoveHandler(_eventAfterOperation, value); } } private static readonly object _eventOperationException = new object(); /// <summary> /// Occurs when a server-side operation is failed to execute. /// </summary> public event OperationExceptionEventHandler OperationException { add { Events.AddHandler (_eventOperationException, value); } remove { Events.RemoveHandler(_eventOperationException, value); } } private static readonly object _eventInitCommand = new object(); /// <summary> /// Occurs when the <see cref="Command"/> is initializing. /// </summary> public event InitCommandEventHandler InitCommand { add { Events.AddHandler (_eventInitCommand, value); } remove { Events.RemoveHandler(_eventInitCommand, value); } } /// <summary> /// Raises the <see cref="BeforeOperation"/> event. /// </summary> /// <param name="op">The <see cref="OperationType"/>.</param> protected virtual void OnBeforeOperation(OperationType op) { if (CanRaiseEvents) { var handler = (OperationTypeEventHandler)Events[_eventBeforeOperation]; if (handler != null) handler(this, new OperationTypeEventArgs(op)); } } /// <summary> /// Raises the <see cref="AfterOperation"/> event. /// </summary> /// <param name="op">The <see cref="OperationType"/>.</param> protected virtual void OnAfterOperation(OperationType op) { if (CanRaiseEvents) { var handler = (OperationTypeEventHandler)Events[_eventAfterOperation]; if (handler != null) handler(this, new OperationTypeEventArgs(op)); } } /// <summary> /// Raises the <see cref="OperationException"/> event. /// </summary> /// <param name="op">The <see cref="OperationType"/>.</param> /// <param name="ex">The <see cref="Exception"/> occurred.</param> protected virtual void OnOperationException(OperationType op, DataException ex) { if (CanRaiseEvents) { var handler = (OperationExceptionEventHandler)Events[_eventOperationException]; if (handler != null) handler(this, new OperationExceptionEventArgs(op, ex)); } throw ex; } #endregion #region Protected Methods private IDataReader ExecuteReaderInternal() { return ExecuteReader(CommandBehavior.Default); } private IDataReader ExecuteReaderInternal(CommandBehavior commandBehavior) { return ExecuteOperation( OperationType.ExecuteReader, () => _dataProvider.GetDataReader(_mappingSchema, SelectCommand.ExecuteReader(commandBehavior))); } private int ExecuteNonQueryInternal() { return ExecuteOperation<int>(OperationType.ExecuteNonQuery, SelectCommand.ExecuteNonQuery); } #endregion #region Parameters private IDbDataParameter[] CreateSpParameters(string spName, object[] parameterValues, bool openNewConnectionToDiscoverParameters) { // Pull the parameters for this stored procedure from // the parameter cache (or discover them & populate the cache) // var spParameters = GetSpParameters(spName, true, openNewConnectionToDiscoverParameters); // DbParameters are bound by name, plain parameters by order // var dbParameters = false; if (parameterValues == null || parameterValues.Length == 0 || parameterValues[0] is IDbDataParameter || parameterValues[0] is IDbDataParameter[]) { // The PrepareParameters method may add some additional parameters. // parameterValues = PrepareParameters(parameterValues); if (parameterValues == null || parameterValues.Length == 0) return spParameters; dbParameters = true; } if (spParameters == null/* || commandParameters.Length == 0*/) { spParameters = new IDbDataParameter[parameterValues.Length]; if (dbParameters) parameterValues.CopyTo(spParameters, 0); else for (var i = 0; i < parameterValues.Length; i++) spParameters[i] = Parameter("?", parameterValues[i]); return spParameters; } if (dbParameters) { // If we receive an array of IDbDataParameter, // we need to copy parameters to the IDbDataParameter[]. // foreach (var spParam in spParameters) { var spParamName = spParam.ParameterName; var found = false; foreach (IDbDataParameter paramWithValue in parameterValues) { var parameterNamesEqual = _dataProvider.ParameterNamesEqual(spParamName, paramWithValue.ParameterName); if (!parameterNamesEqual) { var convertedParameterName = _dataProvider.Convert(paramWithValue.ParameterName, ConvertType.NameToSprocParameter).ToString(); parameterNamesEqual = _dataProvider.ParameterNamesEqual(spParamName, convertedParameterName); } if (!parameterNamesEqual) continue; if (spParam.Direction != paramWithValue.Direction) { if (TraceSwitch.TraceWarning) WriteTraceLine( string.Format( "Stored Procedure '{0}'. Parameter '{1}' has different direction '{2}'. Should be '{3}'.", spName, spParamName, spParam.Direction, paramWithValue.Direction), TraceSwitch.DisplayName); spParam.Direction = paramWithValue.Direction; } if (spParam.Direction != ParameterDirection.Output) spParam.Value = paramWithValue.Value; paramWithValue.ParameterName = spParamName; found = true; break; } if (found == false && ( spParam.Direction == ParameterDirection.Input || spParam.Direction == ParameterDirection.InputOutput)) { if (TraceSwitch.TraceWarning) WriteTraceLine( string.Format("Stored Procedure '{0}'. Parameter '{1}' not assigned.", spName, spParamName), TraceSwitch.DisplayName); spParam.SourceColumn = _dataProvider.Convert(spParamName, ConvertType.SprocParameterToName).ToString(); } } } else { // Assign the provided values to the parameters based on parameter order. // AssignParameterValues(spName, spParameters, parameterValues); } return spParameters; } ///<summary> /// Creates an one-dimension array of <see cref="IDbDataParameter"/> /// from any combination on IDbDataParameter, IDbDataParameter[] or null references. /// Null references are stripped, arrays and single parameters are combined /// into a new array. ///</summary> /// <remarks>When two or more parameters has the same name, /// the first parameter is used, all the rest are ignored.</remarks> ///<param name="parameters">Array of IDbDataParameter, IDbDataParameter[] or null references.</param> ///<returns>An normalized array of <see cref="IDbDataParameter"/> without null references.</returns> ///<exception cref="ArgumentException">The parameter <paramref name="parameters"/> /// contains anything except IDbDataParameter, IDbDataParameter[] or null reference.</exception> public virtual IDbDataParameter[] PrepareParameters(object[] parameters) { if (parameters == null || parameters.Length == 0) return null; // Little optimization. // Check if we have only one single ref parameter. // object refParam = null; foreach (var p in parameters) if (p != null) { if (refParam != null) { refParam = null; break; } refParam = p; } if (refParam is IDbDataParameter[]) { return (IDbDataParameter[])refParam; } if (refParam is IDbDataParameter) { var oneParameterArray = new IDbDataParameter[1]; oneParameterArray[0] = (IDbDataParameter)refParam; return oneParameterArray; } var list = new List<IDbDataParameter>(parameters.Length); var hash = new Dictionary<string, IDbDataParameter>(parameters.Length); foreach (var o in parameters) if (o is IDbDataParameter) { var p = (IDbDataParameter) o; if (!hash.ContainsKey(p.ParameterName)) { list.Add(p); hash.Add(p.ParameterName, p); } } else if (o is IDbDataParameter[]) { foreach (var p in (IDbDataParameter[]) o) if (!hash.ContainsKey(p.ParameterName)) { list.Add(p); hash.Add(p.ParameterName, p); } } else if (o != null && o != DBNull.Value) throw new ArgumentException( Resources.DbManager_NotDbDataParameter, "parameters"); return list.ToArray(); } /// <summary> /// This method is used to attach array of <see cref="IDbDataParameter"/> to a <see cref="IDbCommand"/>. /// </summary> /// <param name="command">The command to which the parameters will be added</param> /// <param name="commandParameters">An array of IDbDataParameters tho be added to command</param> private void AttachParameters(IDbCommand command, IEnumerable<IDbDataParameter> commandParameters) { command.Parameters.Clear(); foreach (var p in commandParameters) _dataProvider.AttachParameter(command, p); } private static readonly Dictionary<string, IDbDataParameter[]> _paramCache = new Dictionary<string, IDbDataParameter[]>(); private static readonly object _paramCacheLock = new object(); /// <summary> /// Resolve at run time the appropriate set of parameters for a stored procedure. /// </summary> /// <param name="spName">The name of the stored procedure.</param> /// <param name="includeReturnValueParameter">Whether or not to include their return value parameter.</param> /// <param name="openNewConnection"></param> /// <returns></returns> protected virtual IDbDataParameter[] DiscoverSpParameters(string spName, bool includeReturnValueParameter, bool openNewConnection) { var con = openNewConnection ? CloneConnection() : _connection; try { if (con.State == ConnectionState.Closed) { ExecuteOperation(OperationType.OpenConnection, con.Open); if (!openNewConnection) _closeConnection = true; } using (var cmd = con.CreateCommand()) { cmd.CommandType = CommandType.StoredProcedure; cmd.CommandText = spName; var res = ExecuteOperation(OperationType.DeriveParameters, () => _dataProvider.DeriveParameters(cmd)); if (openNewConnection) ExecuteOperation(OperationType.CloseConnection, con.Close); if (res == false) return null; if (includeReturnValueParameter == false) { // All known data providers always treat // the return value as first parameter. // cmd.Parameters.RemoveAt(0); } var discoveredParameters = new IDbDataParameter[cmd.Parameters.Count]; for (var i = 0; i < cmd.Parameters.Count; i++) discoveredParameters[i] = (IDbDataParameter)cmd.Parameters[i]; return discoveredParameters; } } finally { if (con != null && openNewConnection) con.Dispose(); } } /// <summary> /// Copies cached parameter array. /// </summary> /// <param name="originalParameters">The original parameter array.</param> /// <returns>The result array.</returns> private IDbDataParameter[] CloneParameters(IDbDataParameter[] originalParameters) { if (originalParameters == null) return null; var clonedParameters = new IDbDataParameter[originalParameters.Length]; for (var i = 0; i < originalParameters.Length; i++) clonedParameters[i] = _dataProvider.CloneParameter(originalParameters[i]); return clonedParameters; } /// <summary> /// Retrieves the set of parameters appropriate for the stored procedure. /// </summary> /// <remarks> /// This method will query the database for this information, /// and then store it in a cache for future requests. /// </remarks> /// <param name="spName">The name of the stored procedure.</param> /// <param name="includeReturnValueParameter">A boolean value indicating /// whether the return value parameter should be included in the results.</param> /// <param name="openNewConnectionToDiscoverParameters"></param> /// <returns>An array of the <see cref="IDbDataParameter"/>.</returns> public IDbDataParameter[] GetSpParameters(string spName, bool includeReturnValueParameter, bool openNewConnectionToDiscoverParameters) { var key = string.Format("{0}:{1}:{2}", GetConnectionHash(), spName, includeReturnValueParameter); IDbDataParameter[] cachedParameters; // It is thread safe enought to check for a key and get its value without a lock. // if (!_paramCache.TryGetValue(key, out cachedParameters)) { lock (_paramCacheLock) { // There is a possible race condition since the operation may take a time. // if (!_paramCache.TryGetValue(key, out cachedParameters)) { cachedParameters = DiscoverSpParameters(spName, includeReturnValueParameter, openNewConnectionToDiscoverParameters); _paramCache.Add(key, cachedParameters); } } } return CloneParameters(cachedParameters); } /// <summary> /// This method assigns an array of values to an array of parameters. /// </summary> /// <param name="spName"></param> /// <param name="commandParameters">array of IDbDataParameters to be assigned values</param> /// <param name="parameterValues">array of objects holding the values to be assigned</param> private void AssignParameterValues(string spName, IDbDataParameter[] commandParameters, object[] parameterValues) { if (commandParameters == null || parameterValues == null) { // Do nothing if we get no data. // return; } var nValues = 0; // Iterate through the parameters, assigning the values from // the corresponding position in the value array. // for (var index = 0; index < commandParameters.Length; index++) { var parameter = commandParameters[index]; if (_dataProvider.IsValueParameter(parameter)) { if (nValues >= parameterValues.Length) throw new ArgumentException(string.Format("Parsing for {0} failed: {1}", spName, GetMissedColumnNames(index, commandParameters))); var value = parameterValues[nValues++]; _dataProvider.SetParameterValue(parameter, value ?? DBNull.Value); } } // We must have the same number of values as we pave parameters to put them in. // if (nValues != parameterValues.Length) throw new ArgumentException(string.Format("Parsing for {0} failed: {1}", spName, GetExceedParameters(nValues, parameterValues))); } string GetMissedColumnNames(int startIndex, IDbDataParameter[] commandParameters) { var columnNames = new List<string>(); for (var index = startIndex; index < commandParameters.Length; index++) { var parameter = commandParameters[index]; if (_dataProvider.IsValueParameter(parameter)) { columnNames.Add(string.Format("{0} {{{1}}}", parameter.ParameterName, parameter.DbType)); } } #if FW4 return "Missed columns: " + string.Join(", ", columnNames); #else return "Missed columns: " + string.Join(", ", columnNames.ToArray()); #endif } static string GetExceedParameters(int startIndex, object[] parameterValues) { var columnNames = new List<string>(); for (var index = startIndex; index < parameterValues.Length; index++) { var parameter = parameterValues[index]; columnNames.Add( parameter == null ? "<null>" : string.Format("{0} {{{1}}}", parameter, parameter.GetType().Name)); } #if FW4 return "Exceed parameters: " + string.Join(", ", columnNames); #else return "Exceed parameters: " + string.Join(", ", columnNames.ToArray()); #endif } /// <overloads> /// Assigns a business object to command parameters. /// </overloads> /// <summary> /// Assigns the <see cref="DataRow"/> to command parameters. /// </summary> /// <include file="Examples1.xml" path='examples/db[@name="AssignParameterValues(DataRow)"]/*' /> /// <remarks> /// The method is used in addition to the <see cref="CreateParameters(object,IDbDataParameter[])"/> method. /// </remarks> /// <param name="dataRow">The <see cref="DataRow"/> to assign.</param> /// <returns>This instance of the <see cref="DbManager"/>.</returns> public DbManager AssignParameterValues(DataRow dataRow) { if (dataRow == null) throw new ArgumentNullException("dataRow"); foreach (DataColumn c in dataRow.Table.Columns) if (c.AutoIncrement == false && c.ReadOnly == false) { var o = dataRow[c.ColumnName]; var name = _dataProvider.Convert(c.ColumnName, GetConvertTypeToParameter()).ToString(); Parameter(name).Value = c.AllowDBNull && _mappingSchema.IsNull(o) ? DBNull.Value : o; } if (_prepared) InitParameters(CommandAction.Select); return this; } /// <summary> /// Assigns a business object to command parameters. /// </summary> /// <remarks> /// The method is used in addition to the <see cref="CreateParameters(object,IDbDataParameter[])"/> method. /// </remarks> /// <include file="Examples1.xml" path='examples/db[@name="AssignParameterValues(object)"]/*' /> /// <param name="obj">An object to assign.</param> /// <returns>This instance of the <see cref="DbManager"/>.</returns> public DbManager AssignParameterValues(object obj) { if (obj == null) throw new ArgumentNullException("obj"); var om = _mappingSchema.GetObjectMapper(obj.GetType()); foreach (MemberMapper mm in om) { var name = _dataProvider.Convert(mm.Name, GetConvertTypeToParameter()).ToString(); if (Command.Parameters.Contains(name)) { var value = mm.GetValue(obj); _dataProvider.SetParameterValue( Parameter(name), value == null || mm.MapMemberInfo.Nullable && _mappingSchema.IsNull(value)? DBNull.Value: value); } } if (_prepared) InitParameters(CommandAction.Select); return this; } private static Array SortArray(Array array, IComparer comparer) { if (array == null) return null; var arrayClone = (Array)array.Clone(); Array.Sort(arrayClone, comparer); return arrayClone; } /// <summary> /// Creates an array of parameters from the <see cref="DataRow"/> object. /// </summary> /// <remarks> /// The method can take an additional parameter list, /// which can be created by using the same method. /// </remarks> /// <include file="Examples.xml" path='examples/db[@name="CreateParameters(DataRow,IDbDataParameter[])"]/*' /> /// <param name="dataRow">The <see cref="DataRow"/> to create parameters.</param> /// <param name="commandParameters">An array of parameters to be added to the result array.</param> /// <returns>An array of parameters.</returns> public IDbDataParameter[] CreateParameters( DataRow dataRow, params IDbDataParameter[] commandParameters) { return CreateParameters(dataRow, null, null, null, commandParameters); } /// <summary> /// Creates an array of parameters from the <see cref="DataRow"/> object. /// </summary> /// <remarks> /// The method can take an additional parameter list, /// which can be created by using the same method. /// </remarks> /// <include file="Examples.xml" path='examples/db[@name="CreateParameters(DataRow,IDbDataParameter[])"]/*' /> /// <param name="dataRow">The <see cref="DataRow"/> to create parameters.</param> /// <param name="outputParameters">Output parameters names.</param> /// <param name="inputOutputParameters">InputOutput parameters names.</param> /// <param name="ignoreParameters">Parameters names to skip.</param> /// <param name="commandParameters">An array of parameters to be added to the result array.</param> /// <returns>An array of parameters.</returns> public IDbDataParameter[] CreateParameters( DataRow dataRow, string[] outputParameters, string[] inputOutputParameters, string[] ignoreParameters, params IDbDataParameter[] commandParameters) { if (dataRow == null) throw new ArgumentNullException("dataRow"); var paramList = new ArrayList(); IComparer comparer = CaseInsensitiveComparer.Default; outputParameters = (string[])SortArray(outputParameters, comparer); inputOutputParameters = (string[])SortArray(inputOutputParameters, comparer); ignoreParameters = (string[])SortArray(ignoreParameters, comparer); foreach (DataColumn c in dataRow.Table.Columns) { if (ignoreParameters != null && Array.BinarySearch(ignoreParameters, c.ColumnName, comparer) >= 0) continue; if (c.AutoIncrement || c.ReadOnly) continue; var name = _dataProvider.Convert(c.ColumnName, GetConvertTypeToParameter()).ToString(); var parameter = c.AllowDBNull ? NullParameter(name, dataRow[c.ColumnName]) : Parameter (name, dataRow[c.ColumnName]); if (outputParameters != null && Array.BinarySearch(outputParameters, c.ColumnName, comparer) >= 0) parameter.Direction = ParameterDirection.Output; else if (inputOutputParameters != null && Array.BinarySearch(inputOutputParameters, c.ColumnName, comparer) >= 0) parameter.Direction = ParameterDirection.InputOutput; paramList.Add(parameter); } if (commandParameters != null) paramList.AddRange(commandParameters); return (IDbDataParameter[])paramList.ToArray(typeof(IDbDataParameter)); } /// <summary> /// Creates an array of parameters from a business object. /// </summary> /// <remarks> /// The method can take an additional parameter list, /// which can be created by using the same method. /// </remarks> /// <include file="Examples.xml" path='examples/db[@name="CreateParameters(object,IDbDataParameter[])"]/*' /> /// <param name="obj">An object.</param> /// <param name="commandParameters">An array of parameters to be added to the result array.</param> /// <returns>An array of parameters.</returns> public IDbDataParameter[] CreateParameters( object obj, params IDbDataParameter[] commandParameters) { return CreateParameters(obj, null, null, null, commandParameters); } /// <summary> /// Creates an array of parameters from a business object. /// </summary> /// <remarks> /// The method can take an additional parameter list, /// which can be created by using the same method. /// </remarks> /// <include file="Examples.xml" path='examples/db[@name="CreateParameters(object,IDbDataParameter[])"]/*' /> /// <param name="obj">An object.</param> /// <param name="outputParameters">Output parameters names.</param> /// <param name="inputOutputParameters">InputOutput parameters names.</param> /// <param name="ignoreParameters">Parameters names to skip.</param> /// <param name="commandParameters">An array of parameters to be added to the result array.</param> /// <returns>An array of parameters.</returns> public IDbDataParameter[] CreateParameters( object obj, string[] outputParameters, string[] inputOutputParameters, string[] ignoreParameters, params IDbDataParameter[] commandParameters) { if (obj == null) throw new ArgumentNullException("obj"); var isType = obj is Type; var type = isType? (Type)obj: obj.GetType(); var om = _mappingSchema.GetObjectMapper(type); var paramList = new ArrayList(); var comparer = CaseInsensitiveComparer.Default; outputParameters = (string[])SortArray(outputParameters, comparer); inputOutputParameters = (string[])SortArray(inputOutputParameters, comparer); ignoreParameters = (string[])SortArray(ignoreParameters, comparer); foreach (MemberMapper mm in om) { if (ignoreParameters != null && Array.BinarySearch(ignoreParameters, mm.Name, comparer) >= 0) continue; var value = isType? null: mm.GetValue(obj); var name = _dataProvider.Convert(mm.Name, GetConvertTypeToParameter()).ToString(); var parameter = value == null ? NullParameter(name, value, mm.MapMemberInfo.NullValue) : (mm.DbType != DbType.Object) ? Parameter(name, value, mm.DbType): Parameter(name, value); if (outputParameters != null && Array.BinarySearch(outputParameters, mm.Name, comparer) >= 0) parameter.Direction = ParameterDirection.Output; else if (inputOutputParameters != null && Array.BinarySearch(inputOutputParameters, mm.Name, comparer) >= 0) parameter.Direction = ParameterDirection.InputOutput; paramList.Add(parameter); } if (commandParameters != null) paramList.AddRange(commandParameters); return (IDbDataParameter[])paramList.ToArray(typeof(IDbDataParameter)); } /// <summary> /// Maps all parameters returned from the server to all given objects. /// </summary> /// <param name="returnValueMember">Name of a <see cref="MemberMapper"/> to map return value.</param> /// <param name="obj">An <see cref="System.Object"/> to map from command parameters.</param> public void MapOutputParameters( string returnValueMember, object obj) { var dest = _mappingSchema.GetDataDestination(obj); foreach (IDbDataParameter parameter in Command.Parameters) { var ordinal = -1; switch (parameter.Direction) { case ParameterDirection.InputOutput: case ParameterDirection.Output: ordinal = dest.GetOrdinal( _dataProvider.Convert(parameter.ParameterName, ConvertType.SprocParameterToName).ToString()); break; case ParameterDirection.ReturnValue: if (returnValueMember != null) { if (!returnValueMember.StartsWith("@") && dest is ObjectMapper) { var om = (ObjectMapper) dest; var ma = om.TypeAccessor[returnValueMember]; if (ma != null) { ma.SetValue(obj, _mappingSchema.ConvertChangeType(parameter.Value, ma.Type)); continue; } } else returnValueMember = returnValueMember.Substring(1); ordinal = dest.GetOrdinal(returnValueMember); } break; } if (ordinal >= 0) dest.SetValue(obj, ordinal, _mappingSchema.ConvertChangeType(parameter.Value, dest.GetFieldType(ordinal))); } } /// <summary> /// Maps all parameters returned from the server to an object. /// </summary> /// <param name="obj">An <see cref="System.Object"/> to map from command parameters.</param> public void MapOutputParameters(object obj) { MapOutputParameters(null, obj); } /// <summary> /// Maps all parameters returned from the server to all given objects. /// </summary> /// <param name="returnValueMember">Name of the member used to map the /// return value. Can be null.</param> /// <param name="objects">An array of <see cref="System.Object"/> to map /// from command parameters.</param> public void MapOutputParameters(string returnValueMember, params object[] objects) { if (objects == null) return; foreach (var obj in objects) MapOutputParameters(returnValueMember, obj); } /// <summary> /// Maps all parameters returned from the server to an object. /// </summary> /// <param name="objects">An array of <see cref="System.Object"/> to map /// from command parameters.</param> public void MapOutputParameters(params object[] objects) { MapOutputParameters(null, objects); } /// <overloads> /// Adds a parameter to the <see cref="Command"/> or returns existing one. /// </overloads> /// <summary> /// Returns an existing parameter. /// </summary> /// <remarks> /// The method can be used to retrieve return and output parameters. /// </remarks> /// <include file="Examples1.xml" path='examples/db[@name="Parameter(string)"]/*' /> /// <param name="parameterName">The name of the parameter.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter Parameter(string parameterName) { return _dataProvider.GetParameter(Command, parameterName); } /// <summary> /// Adds an input parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the /// <see cref="System.Data.ParameterDirection">ParameterDirection.Input</see> type. /// </remarks> /// <include file="Examples1.xml" path='examples/db[@name="Parameter(string,object)"]/*' /> /// <param name="parameterName">The name of the parameter.</param> /// <param name="value">The <see cref="System.Object"/> /// that is the value of the parameter.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter Parameter(string parameterName, object value) { return Parameter(ParameterDirection.Input, parameterName, value); } /// <summary> /// Adds an input parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the /// <see cref="System.Data.ParameterDirection">ParameterDirection.Input</see> type. /// </remarks> /// <param name="parameterName">The name of the parameter.</param> /// <param name="dbType">One of the <see cref="DbType"/> values.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter Parameter(string parameterName, DbType dbType) { return Parameter(ParameterDirection.Input, parameterName, dbType); } /// <summary> /// Adds an input parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the /// <see cref="System.Data.ParameterDirection">ParameterDirection.Input</see> type. /// </remarks> /// <param name="parameterName">The name of the parameter.</param> /// <param name="dbType">One of the <see cref="DbType"/> values.</param> /// <param name="size">Size of the parameter.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter Parameter(string parameterName, DbType dbType, int size) { return Parameter(ParameterDirection.Input, parameterName, dbType, size); } /// <summary> /// Adds an input parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the /// <see cref="System.Data.ParameterDirection">ParameterDirection.Input</see> type. /// If the parameter is null, it's converted to <see cref="DBNull"/>.<see cref="DBNull.Value"/>. /// </remarks> /// <include file="Examples1.xml" path='examples/db[@name="NullParameter(string,object)"]/*' /> /// <param name="parameterName">The name of the parameter.</param> /// <param name="value">The <see cref="System.Object"/> /// that is the value of the parameter.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter NullParameter(string parameterName, object value) { if (_mappingSchema.IsNull(value)) @value = DBNull.Value; return Parameter(ParameterDirection.Input, parameterName, value); } /// <summary> /// Adds an input parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the /// <see cref="System.Data.ParameterDirection">ParameterDirection.Input</see> type. /// </remarks> /// <param name="parameterName">The name of the parameter.</param> /// <param name="value">The <see cref="System.Object"/> /// that is the value of the parameter.</param> /// <param name="nullValue">The null equivalent to compare with the value.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter NullParameter(string parameterName, object value, object nullValue) { if (value == null || value.Equals(nullValue)) @value = DBNull.Value; return Parameter(ParameterDirection.Input, parameterName, value); } /// <summary> /// Adds an input parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the /// <see cref="System.Data.ParameterDirection">ParameterDirection.Input</see> type. /// </remarks> /// <param name="parameterName">The name of the parameter.</param> /// <param name="value">The <see cref="System.Object"/> /// that is the value of the parameter.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter InputParameter(string parameterName, object value) { return Parameter(ParameterDirection.Input, parameterName, value); } /// <summary> /// Adds an output parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the /// <see cref="System.Data.ParameterDirection">ParameterDirection.Output</see> type. /// </remarks> /// <param name="parameterName">The name of the parameter.</param> /// <param name="value">The <see cref="System.Object"/> /// that is the value of the parameter.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter OutputParameter(string parameterName, object value) { return Parameter(ParameterDirection.Output, parameterName, value); } /// <summary> /// Adds an output parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the /// <see cref="System.Data.ParameterDirection">ParameterDirection.Output</see> type. /// </remarks> /// <param name="parameterName">The name of the parameter.</param> /// <param name="dbType">One of the <see cref="DbType"/> values.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter OutputParameter(string parameterName, DbType dbType) { return Parameter(ParameterDirection.Output, parameterName, dbType); } /// <summary> /// Adds an output parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the /// <see cref="System.Data.ParameterDirection">ParameterDirection.Output</see> type. /// </remarks> /// <param name="parameterName">The name of the parameter.</param> /// <param name="dbType">One of the <see cref="DbType"/> values.</param> /// <param name="size">Size of the parameter.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter OutputParameter(string parameterName, DbType dbType, int size) { return Parameter(ParameterDirection.Output, parameterName, dbType, size); } /// <summary> /// Adds an input-output parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the /// <see cref="System.Data.ParameterDirection">ParameterDirection.InputOutput</see> type. /// </remarks> /// <param name="parameterName">The name of the parameter.</param> /// <param name="value">The <see cref="System.Object"/> /// that is the value of the parameter.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter InputOutputParameter(string parameterName, object value) { return Parameter(ParameterDirection.InputOutput,parameterName, value); } /// <summary> /// Adds a return value parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the /// <see cref="System.Data.ParameterDirection">ParameterDirection.ReturnValue</see> type. /// </remarks> /// <param name="parameterName">The name of the parameter.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter ReturnValue(string parameterName) { return Parameter(ParameterDirection.ReturnValue, parameterName, null); } /// <summary> /// Adds a parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the specified /// <see cref="System.Data.ParameterDirection"/> type. /// </remarks> /// <param name="parameterDirection">One of the <see cref="System.Data.ParameterDirection"/> values.</param> /// <param name="parameterName">The name of the parameter.</param> /// <param name="value">The <see cref="System.Object"/> /// that is the value of the parameter.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter Parameter( ParameterDirection parameterDirection, string parameterName, object value) { var parameter = _dataProvider.CreateParameterObject(Command); parameter.ParameterName = parameterName; parameter.Direction = parameterDirection; _dataProvider.SetParameterValue(parameter, value ?? DBNull.Value); return parameter; } /// <summary> /// Adds a parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the specified /// <see cref="System.Data.ParameterDirection"/> type. /// </remarks> /// <param name="parameterDirection">One of the <see cref="System.Data.ParameterDirection"/> values.</param> /// <param name="parameterName">The name of the parameter.</param> /// <param name="value">The <see cref="System.Object"/> /// that is the value of the parameter.</param> /// <param name="dbType">One of the <seealso cref="DbType"/> values.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter Parameter( ParameterDirection parameterDirection, string parameterName, object value, DbType dbType) { var parameter = _dataProvider.CreateParameterObject(Command); parameter.ParameterName = parameterName; parameter.Direction = parameterDirection; parameter.DbType = _dataProvider.GetParameterDbType(dbType); _dataProvider.SetParameterValue(parameter, value ?? DBNull.Value); return parameter; } /// <summary> /// Adds an input parameter to the <see cref="Command"/>. /// </summary> /// <param name="parameterName">The name of the parameter.</param> /// <param name="value">The <see cref="System.Object"/> /// that is the value of the parameter.</param> /// <param name="dbType">One of the <seealso cref="DbType"/> values.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter Parameter( string parameterName, object value, DbType dbType) { return Parameter(ParameterDirection.Input, parameterName, value, dbType); } /// <summary> /// Adds a parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the specified /// <see cref="System.Data.ParameterDirection"/> type. /// </remarks> /// <param name="parameterDirection">One of the <see cref="System.Data.ParameterDirection"/> values.</param> /// <param name="parameterName">The name of the parameter.</param> /// <param name="value">The <see cref="System.Object"/> /// that is the value of the parameter.</param> /// <param name="dbType">One of the <seealso cref="DbType"/> values.</param> /// <param name="size">Size of the parameter.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter Parameter( ParameterDirection parameterDirection, string parameterName, object value, DbType dbType, int size) { var parameter = _dataProvider.CreateParameterObject(Command); parameter.ParameterName = parameterName; parameter.Direction = parameterDirection; parameter.DbType = dbType; parameter.Size = size; _dataProvider.SetParameterValue(parameter, value); return parameter; } /// <summary> /// Adds a parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the specified /// <see cref="System.Data.ParameterDirection"/> type. /// </remarks> /// <param name="parameterDirection">One of the <see cref="System.Data.ParameterDirection"/> values.</param> /// <param name="parameterName">The name of the parameter.</param> /// <param name="value">The <see cref="System.Object"/> /// that is the value of the parameter.</param> /// <param name="typeName">User defined type name for a table-valued parameter.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter Parameter( ParameterDirection parameterDirection, string parameterName, object value, string typeName) { var parameter = _dataProvider.CreateParameterObject(Command); parameter.ParameterName = parameterName; parameter.Direction = parameterDirection; _dataProvider.SetUserDefinedType(parameter, typeName); _dataProvider.SetParameterValue (parameter, value); return parameter; } /// <summary> /// Adds an input parameter to the <see cref="Command"/>. /// </summary> /// <param name="parameterName">The name of the parameter.</param> /// <param name="value">The <see cref="System.Object"/> /// that is the value of the parameter.</param> /// <param name="dbType">One of the <seealso cref="DbType"/> values.</param> /// <param name="size">Size of the parameter.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter Parameter( string parameterName, object value, DbType dbType, int size) { return Parameter(ParameterDirection.Input, parameterName, value, dbType, size); } /// <summary> /// Adds a parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the specified /// <see cref="System.Data.ParameterDirection"/> type. /// </remarks> /// <param name="parameterDirection">One of the <see cref="System.Data.ParameterDirection"/> values.</param> /// <param name="parameterName">The name of the parameter.</param> /// <param name="dbType">One of the <seealso cref="DbType"/> values.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter Parameter( ParameterDirection parameterDirection, string parameterName, DbType dbType) { var parameter = _dataProvider.CreateParameterObject(Command); parameter.ParameterName = parameterName; parameter.Direction = parameterDirection; parameter.DbType = dbType; return parameter; } /// <summary> /// Adds a parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the specified /// <see cref="System.Data.ParameterDirection"/> type. /// </remarks> /// <param name="parameterDirection">One of the <see cref="System.Data.ParameterDirection"/> values.</param> /// <param name="parameterName">The name of the parameter.</param> /// <param name="dbType">One of the <seealso cref="DbType"/> values.</param> /// <param name="size">Size of the parameter.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter Parameter( ParameterDirection parameterDirection, string parameterName, DbType dbType, int size) { var parameter = _dataProvider.CreateParameterObject(Command); parameter.ParameterName = parameterName; parameter.Direction = parameterDirection; parameter.DbType = dbType; parameter.Size = size; return parameter; } /// <summary> /// Creates an input parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the /// <see cref="System.Data.ParameterDirection">ParameterDirection.Input</see> type /// and <see cref="System.Data.DataRowVersion">DataRowVersion.Current</see> type. /// </remarks> /// <param name="parameterName">The name of the parameter.</param> /// <param name="dbType">One of the <see cref="DbType"/> values.</param> /// <param name="size">Size of the parameter.</param> /// <param name="sourceColumn">Source column for a parameter in the <see cref="DataTable"/>.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter Parameter( string parameterName, DbType dbType, int size, string sourceColumn) { var param = Parameter(ParameterDirection.Input, parameterName, dbType, size); param.SourceColumn = sourceColumn; param.SourceVersion = DataRowVersion.Current; return param; } /// <summary> /// Creates an input parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the /// <see cref="System.Data.ParameterDirection">ParameterDirection.Input</see> type /// and <see cref="System.Data.DataRowVersion">DataRowVersion.Current</see> type. /// </remarks> /// <param name="parameterName">The name of the parameter.</param> /// <param name="dbType">One of the <see cref="DbType"/> values.</param> /// <param name="sourceColumn">Source column for a parameter in the <see cref="DataTable"/>.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter Parameter( string parameterName, DbType dbType, string sourceColumn) { var param = Parameter(ParameterDirection.Input, parameterName, dbType); param.SourceColumn = sourceColumn; param.SourceVersion = DataRowVersion.Current; return param; } /// <summary> /// Creates an input parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the /// <see cref="System.Data.ParameterDirection">ParameterDirection.Input</see> type /// and <see cref="System.Data.DataRowVersion">DataRowVersion.Current</see> type. /// </remarks> /// <param name="parameterName">The name of the parameter.</param> /// <param name="dbType">One of the <see cref="DbType"/> values.</param> /// <param name="size">Size of the parameter.</param> /// <param name="sourceColumn">Source column for a parameter in the <see cref="DataTable"/>.</param> /// <param name="dataRowVersion">Version of data to use for a parameter in the <see cref="DataTable"/>.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter Parameter( string parameterName, DbType dbType, int size, string sourceColumn, DataRowVersion dataRowVersion) { var param = Parameter(ParameterDirection.Input, parameterName, dbType, size); param.SourceColumn = sourceColumn; param.SourceVersion = dataRowVersion; return param; } /// <summary> /// Creates an input parameter to the <see cref="Command"/>. /// </summary> /// <remarks> /// The method creates a parameter with the /// <see cref="System.Data.ParameterDirection">ParameterDirection.Input</see> type /// and <see cref="System.Data.DataRowVersion">DataRowVersion.Current</see> type. /// </remarks> /// <param name="parameterName">The name of the parameter.</param> /// <param name="dbType">One of the <see cref="DbType"/> values.</param> /// <param name="sourceColumn">Source column for a parameter in the <see cref="DataTable"/>.</param> /// <param name="dataRowVersion">Version of data to use for a parameter in the <see cref="DataTable"/>.</param> /// <returns>The <see cref="IDbDataParameter"/> object.</returns> public IDbDataParameter Parameter( string parameterName, DbType dbType, string sourceColumn, DataRowVersion dataRowVersion) { var param = Parameter(ParameterDirection.Input, parameterName, dbType); param.SourceColumn = sourceColumn; param.SourceVersion = dataRowVersion; return param; } public ConvertType GetConvertTypeToParameter() { return Command.CommandType == CommandType.StoredProcedure ? ConvertType.NameToSprocParameter: ConvertType.NameToCommandParameter; } #endregion #region SetCommand /// <summary> /// Specifies the action that command is supposed to perform, i.e. Select, Insert, Update, Delete. /// It is used in Execute methods of the <see cref="DbManager"/> class to identify command instance /// to be used. /// </summary> enum CommandAction { Select, Insert, Update, Delete } private bool _executed; private bool _prepared; private IDbDataParameter[] _selectCommandParameters; private IDbDataParameter[] _insertCommandParameters; private IDbDataParameter[] _updateCommandParameters; private IDbDataParameter[] _deleteCommandParameters; private void SetCommand(CommandAction commandAction, IDbCommand command) { switch (commandAction) { case CommandAction.Select: _selectCommand = command; break; case CommandAction.Insert: _insertCommand = command; break; case CommandAction.Update: _updateCommand = command; break; case CommandAction.Delete: _deleteCommand = command; break; } } private IDbCommand GetCommand(CommandAction commandAction) { switch (commandAction) { default: //case CommandAction.Select: return SelectCommand; case CommandAction.Insert: return InsertCommand; case CommandAction.Update: return UpdateCommand; case CommandAction.Delete: return DeleteCommand; } } private IDbCommand GetCommand(CommandAction commandAction, CommandType commandType) { IDbCommand command; switch (commandAction) { default : command = _selectCommand; break; case CommandAction.Insert : command = _insertCommand; break; case CommandAction.Update : command = _updateCommand; break; case CommandAction.Delete : command = _deleteCommand; break; } if (command != null && !DataProvider.CanReuseCommand(command, commandType)) { command.Dispose(); switch (commandAction) { default : _selectCommand = null; break; case CommandAction.Insert : _insertCommand = null; break; case CommandAction.Update : _updateCommand = null; break; case CommandAction.Delete : _deleteCommand = null; break; } } return GetCommand(commandAction); } private void SetCommandParameters(CommandAction commandAction, IDbDataParameter[] commandParameters) { switch (commandAction) { case CommandAction.Select: _selectCommandParameters = commandParameters; break; case CommandAction.Insert: _insertCommandParameters = commandParameters; break; case CommandAction.Update: _updateCommandParameters = commandParameters; break; case CommandAction.Delete: _deleteCommandParameters = commandParameters; break; } } private IDbDataParameter[] GetCommandParameters(CommandAction commandAction) { switch (commandAction) { default: //case CommandAction.Select: return _selectCommandParameters; case CommandAction.Insert: return _insertCommandParameters; case CommandAction.Update: return _updateCommandParameters; case CommandAction.Delete: return _deleteCommandParameters; } } private DbManager SetCommand( CommandAction commandAction, CommandType commandType, string commandText, params IDbDataParameter[] commandParameters) { if (_executed) { _executed = false; _prepared = false; } PrepareCommand(commandAction, commandType, commandText, commandParameters); return this; } private DbManager SetSpCommand( CommandAction commandAction, string spName, bool openNewConnectionToDiscoverParameters, params object[] parameterValues) { return SetCommand( commandAction, CommandType.StoredProcedure, spName, CreateSpParameters(spName, parameterValues, openNewConnectionToDiscoverParameters)); } private DbManager SetSpCommand( CommandAction commandAction, string spName, params object[] parameterValues) { return SetCommand( commandAction, CommandType.StoredProcedure, spName, CreateSpParameters(spName, parameterValues, Configuration.OpenNewConnectionToDiscoverParameters)); } #region Select /// <summary> /// Creates a SQL statement. /// </summary> /// <param name="commandText">The command text to execute.</param> /// <returns>Current instance.</returns> public DbManager SetCommand( string commandText) { return SetCommand(CommandAction.Select, CommandType.Text, commandText, null); } /// <summary> /// Creates a SQL statement. /// </summary> /// <param name="commandType">The <see cref="System.Data.CommandType"/> (stored procedure, text, etc.)</param> /// <param name="commandText">The command text to execute.</param> /// <returns>Current instance.</returns> public DbManager SetCommand( CommandType commandType, string commandText) { return SetCommand(CommandAction.Select, commandType, commandText, null); } /// <summary> /// Creates a SQL statement. /// </summary> /// <remarks> /// The method can be used to create the <i>INSERT</i>, <i>UPDATE</i>, and <i>DELETE</i> SQL statements. /// </remarks> /// <param name="commandText">The command text to execute.</param> /// <param name="commandParameters">An array of parameters used to executes the command.</param> /// <returns>Current instance.</returns> public DbManager SetCommand( string commandText, params IDbDataParameter[] commandParameters) { return SetCommand(CommandAction.Select, CommandType.Text, commandText, commandParameters); } /// <summary> /// Creates a SQL statement. /// </summary> /// <param name="commandType">The <see cref="System.Data.CommandType"/> (stored procedure, text, etc.)</param> /// <param name="commandText">The command text to execute.</param> /// <param name="commandParameters">An array of parameters used to executes the command.</param> /// <returns>Current instance.</returns> public DbManager SetCommand( CommandType commandType, string commandText, params IDbDataParameter[] commandParameters) { return SetCommand(CommandAction.Select, commandType, commandText, commandParameters); } /// <summary> /// Creates a command to be executed as a stored procedure using the provided parameter values. /// </summary> /// <remarks> /// The method queries the database to discover the parameters for the stored procedure /// (the first time each stored procedure is called), /// and assign the values based on parameter order. /// </remarks> /// <param name="spName">The name of the stored procedure</param> /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param> /// <returns>Current instance.</returns> public DbManager SetSpCommand( string spName, params object[] parameterValues) { return SetSpCommand(CommandAction.Select, spName, parameterValues); } public DbManager SetSpCommand( string spName, bool openNewConnectionToDiscoverParameters, params object[] parameterValues) { return SetSpCommand(CommandAction.Select, spName, openNewConnectionToDiscoverParameters, parameterValues); } public DbManager SetCommand(SqlQuery sql, params IDbDataParameter[] commandParameters) { var sb = new StringBuilder(); DataProvider.CreateSqlProvider().BuildSql(0, sql, sb, 0, 0, false); var command = sb.ToString(); if (TraceSwitch.TraceInfo) { var info = string.Format("{0} {1}\n{2}", DataProvider.Name, ConfigurationString, command); if (commandParameters != null && commandParameters.Length > 0) foreach (var p in commandParameters) info += string.Format("\n{0}\t{1}", p.ParameterName, p.Value); WriteTraceLine(info, TraceSwitch.DisplayName); } return SetCommand(command, commandParameters); } #endregion #region Insert /// <summary> /// Creates an Insert SQL statement. /// </summary> /// <remarks> /// The method can be used to create the <i>INSERT</i>, <i>UPDATE</i>, and <i>DELETE</i> SQL statements. /// </remarks> /// <param name="commandText">The command text to execute.</param> /// <param name="commandParameters">An array of parameters used to executes the command.</param> /// <returns>Current instance.</returns> public DbManager SetInsertCommand( string commandText, params IDbDataParameter[] commandParameters) { return SetCommand( CommandAction.Insert, CommandType.Text, commandText, commandParameters); } /// <summary> /// Creates an Insert SQL statement. /// </summary> /// <param name="commandType">The <see cref="System.Data.CommandType"/> (stored procedure, text, etc.)</param> /// <param name="commandText">The command text to execute.</param> /// <param name="commandParameters">An array of parameters used to executes the command.</param> /// <returns>Current instance.</returns> public DbManager SetInsertCommand( CommandType commandType, string commandText, params IDbDataParameter[] commandParameters) { return SetCommand( CommandAction.Insert, commandType, commandText, commandParameters); } /// <summary> /// Creates an Insert command to be executed as a stored procedure using the provided parameter values. /// </summary> /// <remarks> /// The method queries the database to discover the parameters for the stored procedure /// (the first time each stored procedure is called), /// and assign the values based on parameter order. /// </remarks> /// <param name="spName">The name of the stored procedure</param> /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param> /// <returns>Current instance.</returns> public DbManager SetInsertSpCommand( string spName, params object[] parameterValues) { return SetSpCommand(CommandAction.Insert, spName, parameterValues); } #endregion #region Update /// <summary> /// Creates an Update SQL statement. /// </summary> /// <remarks> /// The method can be used to create the <i>INSERT</i>, <i>UPDATE</i>, and <i>DELETE</i> SQL statements. /// </remarks> /// <param name="commandText">The command text to execute.</param> /// <param name="commandParameters">An array of parameters used to executes the command.</param> /// <returns>Current instance.</returns> public DbManager SetUpdateCommand( string commandText, params IDbDataParameter[] commandParameters) { return SetCommand( CommandAction.Update, CommandType.Text, commandText, commandParameters); } /// <summary> /// Creates an Update SQL statement. /// </summary> /// <param name="commandType">The <see cref="System.Data.CommandType"/> (stored procedure, text, etc.)</param> /// <param name="commandText">The command text to execute.</param> /// <param name="commandParameters">An array of parameters used to executes the command.</param> /// <returns>Current instance.</returns> public DbManager SetUpdateCommand( CommandType commandType, string commandText, params IDbDataParameter[] commandParameters) { return SetCommand( CommandAction.Update, commandType, commandText, commandParameters); } /// <summary> /// Creates an Update command to be executed as a stored procedure using the provided parameter values. /// </summary> /// <remarks> /// The method queries the database to discover the parameters for the stored procedure /// (the first time each stored procedure is called), /// and assign the values based on parameter order. /// </remarks> /// <param name="spName">The name of the stored procedure</param> /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param> /// <returns>Current instance.</returns> public DbManager SetUpdateSpCommand( string spName, params object[] parameterValues) { return SetSpCommand(CommandAction.Update, spName, parameterValues); } #endregion #region Delete /// <summary> /// Creates a Delete SQL statement. /// </summary> /// <remarks> /// The method can be used to create the <i>INSERT</i>, <i>UPDATE</i>, and <i>DELETE</i> SQL statements. /// </remarks> /// <param name="commandText">The command text to execute.</param> /// <param name="commandParameters">An array of parameters used to executes the command.</param> /// <returns>Current instance.</returns> public DbManager SetDeleteCommand( string commandText, params IDbDataParameter[] commandParameters) { return SetCommand( CommandAction.Delete, CommandType.Text, commandText, commandParameters); } /// <summary> /// Creates a Delete SQL statement. /// </summary> /// <param name="commandType">The <see cref="System.Data.CommandType"/> (stored procedure, text, etc.)</param> /// <param name="commandText">The command text to execute.</param> /// <param name="commandParameters">An array of parameters used to executes the command.</param> /// <returns>Current instance.</returns> public DbManager SetDeleteCommand( CommandType commandType, string commandText, params IDbDataParameter[] commandParameters) { return SetCommand( CommandAction.Delete, commandType, commandText, commandParameters); } /// <summary> /// Creates a Delete command to be executed as a stored procedure using the provided parameter values. /// </summary> /// <remarks> /// The method queries the database to discover the parameters for the stored procedure /// (the first time each stored procedure is called), /// and assign the values based on parameter order. /// </remarks> /// <param name="spName">The name of the stored procedure</param> /// <param name="parameterValues">An array of objects to be assigned as the input values of the stored procedure</param> /// <returns>Current instance.</returns> public DbManager SetDeleteSpCommand( string spName, params object[] parameterValues) { return SetSpCommand(CommandAction.Delete, spName, parameterValues); } #endregion #endregion #region Prepare private void PrepareCommand( CommandAction commandAction, CommandType commandType, string commandText, IDbDataParameter[] commandParameters) { DataProvider.PrepareCommand(ref commandType, ref commandText, ref commandParameters); LastQuery = commandText; var command = GetCommand(commandAction, commandType, commandText); SetCommand (commandAction, command); SetCommandParameters(commandAction, commandParameters); if (commandParameters != null) { AttachParameters(command, commandParameters); } } /// <summary> /// Prepares a command for execution. /// </summary> /// <returns>Current instance.</returns> public DbManager Prepare() { var command = GetCommand(CommandAction.Select); if (InitParameters(CommandAction.Select) == false) ExecuteOperation(OperationType.PrepareCommand, command.Prepare); _prepared = true; return this; } bool InitParameters(CommandAction commandAction) { var prepare = false; var commandParameters = GetCommandParameters(commandAction); if (commandParameters != null) { foreach (var p in commandParameters) { if (_dataProvider.InitParameter(p)) continue; // It forces parameter's filed 'MetaType' to be set. // Same for p.Size = p.Size below. // p.DbType = p.DbType; if (p.Value is string) { var len = ((string)p.Value).Length; if (p.Size < len) { p.Size = len; prepare = true; } else p.Size = p.Size; } else if (p.Value is DBNull) { p.Size = 1; } else if (p.Value is byte[]) { var len = ((byte[])p.Value).Length; if (p.Size < len) { p.Size = len; prepare = true; } else p.Size = p.Size; } else if (p.Value is char[]) { var len = ((char[])p.Value).Length; if (p.Size < len) { p.Size = len; prepare = true; } else p.Size = p.Size; } else if (p.Value is decimal) { SqlDecimal d = (decimal)p.Value; if (p.Precision < d.Precision) { p.Precision = d.Precision; prepare = true; } else p.Precision = p.Precision; if (p.Scale < d.Scale) { p.Scale = d.Scale; prepare = true; } else p.Scale = p.Scale; } } // Re-prepare command to avoid truncation. // if (prepare) { var command = GetCommand(commandAction); AttachParameters(command, commandParameters); command.Prepare(); } } return prepare; } #endregion #region ExecuteForEach /// <summary> /// Executes a SQL statement for a given collection of objects and /// returns the number of rows affected. /// </summary> /// <remarks> /// The method prepares the <see cref="Command"/> object /// and calls the <see cref="ExecuteNonQuery()"/> method for each item of the list. /// </remarks> /// <include file="Examples1.xml" path='examples/db[@name="Execute(CommandType,string,IList)"]/*' /> /// <param name="collection">The list of objects used to execute the command.</param> /// <returns>The number of rows affected by the command.</returns> public int ExecuteForEach(ICollection collection) { var rowsTotal = 0; if (collection != null && collection.Count != 0) { var initParameters = true; foreach (var o in collection) { if (initParameters) { initParameters = false; var parameters = GetCommandParameters(CommandAction.Select); if (parameters == null || parameters.Length == 0) { parameters = CreateParameters(o); SetCommandParameters(CommandAction.Select, parameters); AttachParameters(SelectCommand, parameters); Prepare(); } } AssignParameterValues(o); rowsTotal += ExecuteNonQueryInternal(); MapOutputParameters(o); } } return rowsTotal; } /// <summary> /// Executes a SQL statement for a given collection of objects and /// returns the number of rows affected. /// </summary> /// <remarks> /// The method prepares the <see cref="Command"/> object /// and calls the <see cref="ExecuteNonQuery()"/> method for each item of the list. /// </remarks> /// <include file="Examples1.xml" path='examples/db[@name="Execute(CommandType,string,IList)"]/*' /> /// <param name="collection">The list of objects used to execute the command.</param> /// <returns>The number of rows affected by the command.</returns> public int ExecuteForEach<T>(ICollection<T> collection) { var rowsTotal = 0; if (collection != null && collection.Count != 0) { var initParameters = true; foreach (var o in collection) { if (initParameters) { initParameters = false; var parameters = GetCommandParameters(CommandAction.Select); if (parameters == null || parameters.Length == 0) { parameters = CreateParameters(o); SetCommandParameters(CommandAction.Select, parameters); AttachParameters(SelectCommand, parameters); Prepare(); } } AssignParameterValues(o); rowsTotal += ExecuteNonQueryInternal(); MapOutputParameters(o); } } return rowsTotal; } public int ExecuteForEach<T>(int maxBatchSize, IEnumerable<T> collection) { var om = _mappingSchema.GetObjectMapper(typeof(T)); var mms = new List<MemberMapper>(); foreach (MemberMapper mm in om) { var name = _dataProvider.Convert(mm.Name, GetConvertTypeToParameter()).ToString(); if (Command.Parameters.Contains(name)) mms.Add(mm); } return ExecuteForEach( collection, mms.ToArray(), maxBatchSize, obj => CreateParameters(obj)); } public delegate IDbDataParameter[] ParameterProvider<T>(T obj); internal int ExecuteForEach<T>(IEnumerable<T> collection, MemberMapper[] members, int maxBatchSize, ParameterProvider<T> getParameters) { if (collection == null) return 0; var maxRows = Math.Max( Math.Min( Math.Max( members.Length == 0? 1000 : _dataProvider.MaxParameters / members.Length, members.Length), maxBatchSize), 1); var baseSql = SelectCommand.CommandText; var paramName = _dataProvider.Convert(".", ConvertType.NameToQueryParameter).ToString(); var rowsTotal = 0; var nRows = 0; var initParameters = true; var saveCanRaseEvent = _canRaiseEvents; _canRaiseEvents = false; var sb = new StringBuilder(); var rowSql = new List<int>(maxRows); IDbDataParameter[] baseParameters = null; var parameters = new List<IDbDataParameter>(); var hasValue = new List<bool>(); var isPrepared = false; foreach (var obj in collection) { if (initParameters) { initParameters = false; baseParameters = getParameters(obj); if (maxRows != 1) { var n = 0; foreach (var p in baseParameters) n += p.ParameterName.Length + 3 - "{0}".Length + _dataProvider.EndOfSql.Length; maxRows = Math.Max(1, Math.Min(maxRows, _dataProvider.MaxBatchSize / (baseSql.Length + n))); } if (maxRows != 1) baseSql += _dataProvider.EndOfSql; } if (rowSql.Count < maxRows) { // ReSharper disable AccessToModifiedClosure Converter<IDbDataParameter,string> c1 = p => p.ParameterName + nRows; // ReSharper restore AccessToModifiedClosure Converter<IDbDataParameter,string> c2 = p => p.ParameterName; sb .Append("\n") .AppendFormat( baseSql, Array.ConvertAll( baseParameters, baseParameters.Length > 0 && baseParameters[0].ParameterName != paramName? c1 : c2)); rowSql.Add(sb.Length); for (var i = 0; i < members.Length; i++) { var value = members[i].GetValue(obj); var type = members[i].MemberAccessor.Type; var dbType = members[i].GetDbType(); IDbDataParameter p; if ((value == null || value == DBNull.Value) && (dbType == DbType.Binary || type == typeof(byte[])) || type == typeof(System.Data.Linq.Binary)) { p = Parameter(baseParameters[i].ParameterName + nRows, DBNull.Value, DbType.Binary); } else { if (value != null && value.GetType().IsEnum) value = MappingSchema.MapEnumToValue(value, true); p = value != null ? Parameter(baseParameters[i].ParameterName + nRows, value) : Parameter(baseParameters[i].ParameterName + nRows, DBNull.Value, members[i].GetDbType()); } parameters.Add(p); hasValue.Add(value != null); } } else { var n = nRows * members.Length; for (var i = 0; i < members.Length; i++) { var value = members[i].GetValue(obj); if (!hasValue[n + i] && value != null) { isPrepared = false; var type = members[i].MemberAccessor.Type; var dbType = members[i].GetDbType(); if (value.GetType().IsEnum) value = MappingSchema.MapEnumToValue(value, true); IDbDataParameter p; if (dbType != DbType.Object) p = Parameter(baseParameters[i].ParameterName + nRows, value ?? DBNull.Value, dbType); else p = Parameter(baseParameters[i].ParameterName + nRows, value ?? DBNull.Value/*, dbType*/); parameters[n + i] = p; hasValue [n + i] = true; } else { if (value != null && value.GetType().IsEnum) value = MappingSchema.MapEnumToValue(value, true); _dataProvider.SetParameterValue( parameters[n + i], value ?? DBNull.Value); //value == null || members[i].MapMemberInfo.Nullable && _mappingSchema.IsNull(value) // ? DBNull.Value // : value); } } } nRows++; if (nRows >= maxRows) { if (!isPrepared) { SetCommand(sb.ToString(), parameters.ToArray()); Prepare(); isPrepared = true; } else { InitParameters(CommandAction.Select); } var n = ExecuteNonQueryInternal(); if (n > 0) rowsTotal += n; nRows = 0; } } if (nRows > 0) { if (rowSql.Count >= maxRows) { var nps = nRows * members.Length; parameters.RemoveRange(nps, parameters.Count - nps); sb.Length = rowSql[nRows - 1]; } SetCommand(sb.ToString(), parameters.ToArray()); Prepare(); var n = ExecuteNonQueryInternal(); if (n > 0) rowsTotal += n; } _canRaiseEvents = saveCanRaseEvent; return rowsTotal; } /// <summary> /// Executes a SQL statement for the <see cref="DataTable"/> and /// returns the number of rows affected. /// </summary> /// <remarks> /// The method prepares the <see cref="Command"/> object /// and calls the <see cref="ExecuteNonQuery()"/> method for each item /// of the <see cref="DataTable"/>. /// </remarks> /// <include file="Examples1.xml" path='examples/db[@name="Execute(CommandType,string,DataTable)"]/*' /> /// <param name="table">An instance of the <see cref="DataTable"/> class to execute the command.</param> /// <returns>The number of rows affected by the command.</returns> public int ExecuteForEach(DataTable table) { var rowsTotal = 0; if (table != null && table.Rows.Count != 0) { var parameters = GetCommandParameters(CommandAction.Select); if (parameters == null || parameters.Length == 0) { parameters = CreateParameters(table.Rows[0]); SetCommandParameters(CommandAction.Select, parameters); AttachParameters(SelectCommand, parameters); Prepare(); } foreach (DataRow dr in table.Rows) { AssignParameterValues(dr); rowsTotal += ExecuteNonQueryInternal(); } } return rowsTotal; } /// <summary> /// Executes a SQL statement for the first table of the <see cref="DataSet"/> /// and returns the number of rows affected. /// </summary> /// <remarks> /// The method prepares the <see cref="Command"/> object /// and calls the <see cref="ExecuteNonQuery()"/> method for each item of the first table. /// </remarks> /// <include file="Examples1.xml" path='examples/db[@name="Execute(CommandType,string,DataSet)"]/*' /> /// <param name="dataSet">An instance of the <see cref="DataSet"/> class to execute the command.</param> /// <returns>The number of rows affected by the command.</returns> public int ExecuteForEach(DataSet dataSet) { return ExecuteForEach(dataSet.Tables[0]); } /// <summary> /// Executes a SQL statement for the specified table of the <see cref="DataSet"/> /// and returns the number of rows affected. /// </summary> /// <remarks> /// The method prepares the <see cref="Command"/> object /// and calls the <see cref="ExecuteNonQuery()"/> method for each item of the first table. /// </remarks> /// <include file="Examples1.xml" path='examples/db[@name="Execute(CommandType,string,DataSet,string)"]/*' /> /// <param name="dataSet">An instance of the <see cref="DataSet"/> class to execute the command.</param> /// <param name="nameOrIndex">The table name or index. /// name/index.</param> /// <returns>The number of rows affected by the command.</returns> public int ExecuteForEach(DataSet dataSet, NameOrIndexParameter nameOrIndex) { return nameOrIndex.ByName ? ExecuteForEach(dataSet.Tables[nameOrIndex.Name]) : ExecuteForEach(dataSet.Tables[nameOrIndex.Index]); } #endregion #region ExecuteNonQuery /// <summary> /// Executes a SQL statement and returns the number of rows affected. /// </summary> /// <remarks> /// The method can be used to execute the <i>INSERT</i>, <i>UPDATE</i>, and <i>DELETE</i> SQL statements. /// </remarks> /// <include file="Examples1.xml" path='examples/db[@name="ExecuteNonQuery()"]/*' /> /// <returns>The number of rows affected by the command.</returns> public int ExecuteNonQuery() { if (_prepared) InitParameters(CommandAction.Select); return ExecuteNonQueryInternal(); } /// <summary> /// Executes a SQL statement and returns the number of rows affected. /// </summary> /// <remarks> /// The method can be used to execute the <i>INSERT</i>, <i>UPDATE</i>, and <i>DELETE</i> SQL statements. /// </remarks> /// <param name="returnValueMember">Name of a <see cref="MemberMapper"/> to map return value.</param> /// <param name="obj">An <see cref="System.Object"/> to map from command parameters.</param> /// <returns>The number of rows affected by the command.</returns> public int ExecuteNonQuery( string returnValueMember, object obj) { var rowsAffected = ExecuteNonQuery(); MapOutputParameters(returnValueMember, obj); return rowsAffected; } /// <summary> /// Executes a SQL statement and returns the number of rows affected. /// </summary> /// <remarks> /// The method can be used to execute the <i>INSERT</i>, <i>UPDATE</i>, and <i>DELETE</i> SQL statements. /// </remarks> /// <param name="obj">An <see cref="System.Object"/> to map from command parameters.</param> /// <returns>The number of rows affected by the command.</returns> public int ExecuteNonQuery(object obj) { var rowsAffected = ExecuteNonQuery(); MapOutputParameters(null, obj); return rowsAffected; } /// <summary> /// Executes a SQL statement and returns the number of rows affected. /// </summary> /// <remarks> /// The method can be used to execute the <i>INSERT</i>, <i>UPDATE</i>, and <i>DELETE</i> SQL statements. /// </remarks> /// <param name="returnValueMember">Name of a <see cref="MemberMapper"/> to map return value.</param> /// <param name="objects">An array of <see cref="System.Object"/> to map /// from command parameters.</param> /// <returns>The number of rows affected by the command.</returns> public int ExecuteNonQuery( string returnValueMember, params object[] objects) { var rowsAffected = ExecuteNonQuery(); MapOutputParameters(returnValueMember, objects); return rowsAffected; } /// <summary> /// Executes a SQL statement and returns the number of rows affected. /// </summary> /// <remarks> /// The method can be used to execute the <i>INSERT</i>, <i>UPDATE</i>, and <i>DELETE</i> SQL statements. /// </remarks> /// <param name="objects">An array of <see cref="System.Object"/> to map /// from command parameters.</param> /// <returns>The number of rows affected by the command.</returns> public int ExecuteNonQuery(params object[] objects) { var rowsAffected = ExecuteNonQuery(); MapOutputParameters(null, objects); return rowsAffected; } /// <summary> /// Executes several SQL statements at a time using single roundtrip to the server (if supported by data provider). /// </summary> /// <remarks> /// All parameters of the query must be arrays of type corresponding to the type of the parameter. /// The value of the <paramref name="iterations"/> parameter must be equal to the number of elements of each array. /// </remarks> /// <param name="iterations">The number of iterations.</param> /// <returns>The number of rows affected by the command.</returns> public int ExecuteArray(int iterations) { return ExecuteOperation<int>(OperationType.ExecuteNonQuery, () => DataProvider.ExecuteArray(SelectCommand, iterations)); } #endregion #region ExecuteScalar /// <summary> /// Executes the query, and returns the first column of the first row /// in the resultset returned by the query. Extra columns or rows are /// ignored. /// </summary> /// <returns>The first column of the first row in the resultset.</returns> /// <seealso cref="ExecuteScalar(ScalarSourceType, NameOrIndexParameter)"/> public object ExecuteScalar() { if (_prepared) InitParameters(CommandAction.Select); using (var rd = ExecuteReaderInternal(CommandBehavior.Default)) return rd.Read() && rd.FieldCount > 0 ? rd.GetValue(0) : null; } /// <summary> /// Executes the query, and returns the value with specified scalar /// source type. /// </summary> /// <param name="sourceType">The method used to return the scalar /// value.</param> /// <returns><list type="table"> /// <listheader> /// <term>ScalarSourceType</term> /// <description>Return value</description> /// </listheader> /// <item> /// <term>DataReader</term> /// <description>The first column of the first row in the resultset. /// </description> /// </item> /// <item> /// <term>OutputParameter</term> /// <description>The value of the first output or input/output /// parameter returned.</description> /// </item> /// <item> /// <term>ReturnValue</term> /// <description>The value of the "return value" parameter returned. /// </description> /// </item> /// <item> /// <term>AffectedRows</term> /// <description>The number of rows affected.</description> /// </item> /// </list> /// </returns> /// <seealso cref="ExecuteScalar(ScalarSourceType, NameOrIndexParameter)"/> public object ExecuteScalar(ScalarSourceType sourceType) { return ExecuteScalar(sourceType, new NameOrIndexParameter()); } /// <summary> /// Executes the query, and returns the value with specified scalar /// source type. /// </summary> /// <param name="sourceType">The method used to return the scalar value.</param> /// <param name="nameOrIndex">The column name/index or output parameter name/index.</param> /// <returns><list type="table"> /// <listheader> /// <term>ScalarSourceType</term> /// <description>Return value</description> /// </listheader> /// <item> /// <term>DataReader</term> /// <description>The column with specified name or at specified index /// of the first row in the resultset.</description> /// </item> /// <item> /// <term>OutputParameter</term> /// <description>The value of the output or input/output parameter /// returned with specified name or at specified index.</description> /// </item> /// <item> /// <term>ReturnValue</term> /// <description>The value of the "return value" parameter returned. /// The index parameter is ignored.</description> /// </item> /// <item> /// <term>AffectedRows</term> /// <description>The number of rows affected. The index parameter is /// ignored.</description> /// </item> /// </list> /// </returns> public object ExecuteScalar(ScalarSourceType sourceType, NameOrIndexParameter nameOrIndex) { if (_prepared) InitParameters(CommandAction.Select); switch (sourceType) { case ScalarSourceType.DataReader: using (var reader = ExecuteReaderInternal()) if (reader.Read()) return reader.GetValue(nameOrIndex.ByName ? reader.GetOrdinal(nameOrIndex.Name) : nameOrIndex.Index); break; case ScalarSourceType.OutputParameter: ExecuteNonQueryInternal(); if (nameOrIndex.ByName) { var name = (string)_dataProvider.Convert(nameOrIndex.Name, GetConvertTypeToParameter()); return Parameter(name).Value; } var index = nameOrIndex.Index; foreach (IDataParameter p in SelectCommand.Parameters) { // Skip the return value parameter. // if (p.Direction == ParameterDirection.ReturnValue) continue; if (0 == index) return p.Value; --index; } break; case ScalarSourceType.ReturnValue: ExecuteNonQueryInternal(); foreach (IDataParameter p in SelectCommand.Parameters) if (p.Direction == ParameterDirection.ReturnValue) return p.Value; break; case ScalarSourceType.AffectedRows: return ExecuteNonQueryInternal(); default: throw new InvalidEnumArgumentException("sourceType", (int)sourceType, typeof(ScalarSourceType)); } return null; } /// <summary> /// Executes the query, and returns the first column of the first row /// in the resultset returned by the query. Extra columns or rows are /// ignored. /// </summary> /// <returns> /// The first column of the first row in the resultset.</returns> /// <seealso cref="ExecuteScalar{T}(ScalarSourceType, NameOrIndexParameter)"/> public T ExecuteScalar<T>() { var value = _mappingSchema.ConvertChangeType(ExecuteScalar(), typeof(T)); return value == null && typeof(T).IsEnum ? default(T) : (T)value; } /// <summary> /// Executes the query, and returns the value with specified scalar /// source type. /// </summary> /// <param name="sourceType">The method used to return the scalar /// value.</param> /// <returns><list type="table"> /// <listheader> /// <term>ScalarSourceType</term> /// <description>Return value</description> /// </listheader> /// <item> /// <term>DataReader</term> /// <description>The first column of the first row in the resultset. /// </description> /// </item> /// <item> /// <term>OutputParameter</term> /// <description>The value of the first output or input/output /// parameter returned.</description> /// </item> /// <item> /// <term>ReturnValue</term> /// <description>The value of the "return value" parameter returned. /// </description> /// </item> /// <item> /// <term>AffectedRows</term> /// <description>The number of rows affected.</description> /// </item> /// </list> /// </returns> /// <seealso cref="ExecuteScalar{T}(ScalarSourceType, NameOrIndexParameter)"/> public T ExecuteScalar<T>(ScalarSourceType sourceType) { return ExecuteScalar<T>(sourceType, new NameOrIndexParameter()); } /// <summary> /// Executes the query, and returns the value with specified scalar /// source type. /// </summary> /// <param name="sourceType">The method used to return the scalar value.</param> /// <param name="nameOrIndex">The column name/index or output parameter name/index.</param> /// <returns><list type="table"> /// <listheader> /// <term>ScalarSourceType</term> /// <description>Return value</description> /// </listheader> /// <item> /// <term>DataReader</term> /// <description>The column with specified name or at specified index /// of the first row in the resultset.</description> /// </item> /// <item> /// <term>OutputParameter</term> /// <description>The value of the output or input/output parameter /// returned with specified name or at specified index.</description> /// </item> /// <item> /// <term>ReturnValue</term> /// <description>The value of the "return value" parameter returned. /// The index parameter is ignored.</description> /// </item> /// <item> /// <term>AffectedRows</term> /// <description>The number of rows affected. The index parameter is /// ignored.</description> /// </item> /// </list> /// </returns> public T ExecuteScalar<T>(ScalarSourceType sourceType, NameOrIndexParameter nameOrIndex) { return (T)_mappingSchema.ConvertChangeType(ExecuteScalar(sourceType, nameOrIndex), typeof(T)); } #endregion #region ExecuteScalarList /// <summary> /// Executes the query, and returns the array list of values of the /// specified column of the every row in the resultset returned by the /// query. Other columns are ignored. /// </summary> /// <param name="list">The array to fill in.</param> /// <param name="nameOrIndex">The column name/index or output parameter name/index.</param> /// <param name="type">The type of the each element.</param> /// <returns>Array list of values of the specified column of the every /// row in the resultset.</returns> public IList ExecuteScalarList( IList list, Type type, NameOrIndexParameter nameOrIndex) { if (list == null) list = new ArrayList(); if (_prepared) InitParameters(CommandAction.Select); using (var dr = ExecuteReaderInternal()) return _mappingSchema.MapDataReaderToScalarList(dr, nameOrIndex, list, type); } /// <summary> /// Executes the query, and returns the array list of values of first /// column of the every row in the resultset returned by the query. /// Other columns are ignored. /// </summary> /// <param name="list">The array to fill in.</param> /// <param name="type">The type of the each element.</param> /// <returns>Array list of values of first column of the every row in /// the resultset.</returns> public IList ExecuteScalarList(IList list, Type type) { if (list == null) list = new ArrayList(); return ExecuteScalarList(list, type, 0); } /// <summary> /// Executes the query, and returns the array list of values of the /// specified column of the every row in the resultset returned by the /// query. Other columns are ignored. /// </summary> /// <param name="nameOrIndex">The column name/index.</param> /// <param name="type">The type of the each element.</param> /// <returns>Array list of values of the specified column of the every /// row in the resultset.</returns> public ArrayList ExecuteScalarList(Type type, NameOrIndexParameter nameOrIndex) { var list = new ArrayList(); ExecuteScalarList(list, type, nameOrIndex); return list; } /// <summary> /// Executes the query, and returns the array list of values of first /// column of the every row in the resultset returned by the query. /// Other columns are ignored. /// </summary> /// <param name="type">The type of the each element.</param> /// <returns>Array list of values of first column of the every row in /// the resultset.</returns> public ArrayList ExecuteScalarList(Type type) { var list = new ArrayList(); ExecuteScalarList(list, type, 0); return list; } /// <summary> /// Executes the query, and returns the array list of values of the /// specified column of the every row in the resultset returned by the /// query. Other columns are ignored. /// </summary> /// <param name="list">The array to fill in.</param> /// <param name="nameOrIndex">The column name/index or output parameter /// name/index.</param> /// <typeparam name="T">The type of the each element.</typeparam> /// <returns>Array list of values of the specified column of the every /// row in the resultset.</returns> public IList<T> ExecuteScalarList<T>( IList<T> list, NameOrIndexParameter nameOrIndex) { if (list == null) list = new List<T>(); if (_prepared) InitParameters(CommandAction.Select); using (var dr = ExecuteReaderInternal()) return _mappingSchema.MapDataReaderToScalarList(dr, nameOrIndex, list); } /// <summary> /// Executes the query, and returns the array list of values of first /// column of the every row in the resultset returned by the query. /// Other columns are ignored. /// </summary> /// <param name="list">The array to fill in.</param> /// <typeparam name="T">The type of the each element.</typeparam> /// <returns>Array list of values of first column of the every row in /// the resultset.</returns> public IList<T> ExecuteScalarList<T>(IList<T> list) { return ExecuteScalarList(list, 0); } /// <summary> /// Executes the query, and returns the array list of values of the /// specified column of the every row in the resultset returned by the /// query. Other columns are ignored. /// </summary> /// <param name="nameOrIndex">The column name/index or output parameter name/index.</param> /// <typeparam name="T">The type of the each element.</typeparam> /// <returns>Array list of values of the specified column of the every /// row in the resultset.</returns> public List<T> ExecuteScalarList<T>(NameOrIndexParameter nameOrIndex) { var list = new List<T>(); ExecuteScalarList(list, nameOrIndex); return list; } /// <summary> /// Executes the query, and returns the list of values of first /// column of the every row in the resultset returned by the query. /// Other columns are ignored. /// </summary> /// <typeparam name="T">The type of the each element.</typeparam> /// <returns>Array list of values of first column of the every row in /// the resultset.</returns> public List<T> ExecuteScalarList<T>() { var list = new List<T>(); ExecuteScalarList(list, 0); return list; } #endregion #region ExecuteScalarDictionary ///<summary> /// Executes the query, and returns the dictionary. /// The keys are loaded from a column specified by <paramref name="keyField"/> and /// values are loaded from a column specified by <paramref name="valueField"/>. /// Other columns are ignored. ///</summary> ///<param name="dic">The dictionary to add values.</param> ///<param name="keyField">The column name/index to load keys.</param> ///<param name="keyFieldType">The key type.</param> ///<param name="valueField">The column name/index to load values.</param> ///<param name="valueFieldType">The value type.</param> ///<returns>The loaded dictionary.</returns> public IDictionary ExecuteScalarDictionary( IDictionary dic, NameOrIndexParameter keyField, Type keyFieldType, NameOrIndexParameter valueField, Type valueFieldType) { if (dic == null) dic = new Hashtable(); if (_prepared) InitParameters(CommandAction.Select); //object nullValue = _mappingSchema.GetNullValue(type); if (keyField.ByName && keyField.Name.Length > 0 && keyField.Name[0] == '@') keyField = keyField.Name.Substring(1); using (var dr = ExecuteReaderInternal()) { if (dr.Read()) { var keyIndex = keyField.ByName ? dr.GetOrdinal(keyField.Name) : keyField.Index; var valueIndex = valueField.ByName ? dr.GetOrdinal(valueField.Name) : valueField.Index; do { var value = dr[valueIndex]; var key = dr[keyIndex]; if (key == null || key.GetType() != keyFieldType) key = key is DBNull ? null : _mappingSchema.ConvertChangeType(key, keyFieldType); if (value == null || value.GetType() != valueFieldType) value = value is DBNull ? null : _mappingSchema.ConvertChangeType(value, valueFieldType); dic.Add(key, value); } while (dr.Read()); } } return dic; } ///<summary> /// Executes the query, and returns the dictionary. /// The keys are loaded from a column specified by <paramref name="keyField"/> and /// values are loaded from a column specified by <paramref name="valueField"/>. /// Other columns are ignored. ///</summary> ///<param name="keyField">The column name/index to load keys.</param> ///<param name="keyFieldType">The key type.</param> ///<param name="valueField">The column name/index to load values.</param> ///<param name="valueFieldType">The value type.</param> ///<returns>The loaded dictionary.</returns> public Hashtable ExecuteScalarDictionary( NameOrIndexParameter keyField, Type keyFieldType, NameOrIndexParameter valueField, Type valueFieldType) { var table = new Hashtable(); ExecuteScalarDictionary(table, keyField, keyFieldType, valueField, valueFieldType); return table; } ///<summary> /// Executes the query, and returns the dictionary. /// The keys are loaded from a column specified by <paramref name="keyField"/> and /// values are loaded from a column specified by <paramref name="valueField"/>. /// Other columns are ignored. ///</summary> ///<typeparam name="TKey">The key type.</typeparam> ///<typeparam name="T">The value type.</typeparam> ///<param name="dic">The dictionary to add values.</param> ///<param name="keyField">The column name/index to load keys.</param> ///<param name="valueField">The column name/index to load values.</param> ///<returns>The loaded dictionary.</returns> public IDictionary<TKey,T> ExecuteScalarDictionary<TKey,T>( IDictionary<TKey,T> dic, NameOrIndexParameter keyField, NameOrIndexParameter valueField) { if (dic == null) dic = new Dictionary<TKey,T>(); if (_prepared) InitParameters(CommandAction.Select); //object nullValue = _mappingSchema.GetNullValue(type); var keyFieldType = typeof(TKey); var valueFieldType = typeof(T); using (var dr = ExecuteReaderInternal()) if (dr.Read()) { var keyIndex = keyField.ByName ? dr.GetOrdinal(keyField.Name) : keyField.Index; var valueIndex = valueField.ByName ? dr.GetOrdinal(valueField.Name) : valueField.Index; do { var value = dr[valueIndex]; var key = dr[keyIndex]; if (key == null || key.GetType() != keyFieldType) key = key is DBNull ? null : _mappingSchema.ConvertChangeType(key, keyFieldType); if (value == null || value.GetType() != valueFieldType) value = value is DBNull ? null : _mappingSchema.ConvertChangeType(value, valueFieldType); dic.Add((TKey) key, (T) value); } while (dr.Read()); } return dic; } ///<summary> /// Executes the query, and returns the dictionary. /// The keys are loaded from a column specified by <paramref name="keyField"/> and /// values are loaded from a column specified by <paramref name="valueField"/>. /// Other columns are ignored. ///</summary> ///<typeparam name="TKey">The key type.</typeparam> ///<typeparam name="T">The value type.</typeparam> ///<param name="keyField">The column name/index to load keys.</param> ///<param name="valueField">The column name/index to load values.</param> ///<returns>The loaded dictionary.</returns> public Dictionary<TKey,T> ExecuteScalarDictionary<TKey,T>( NameOrIndexParameter keyField, NameOrIndexParameter valueField) { var dic = new Dictionary<TKey,T>(); ExecuteScalarDictionary(dic, keyField, valueField); return dic; } #endregion #region ExecuteScalarDictionary (Index) ///<summary> /// Executes the query, and returns the dictionary. /// The keys are loaded from columns specified by <paramref name="index"/> and /// values are loaded from a column specified by <paramref name="valueField"/>. /// Other columns are ignored. ///</summary> ///<param name="dic">The dictionary to add values.</param> ///<param name="index">The <see cref="MapIndex"/> of the key columns.</param> ///<param name="valueField">The column name/index to load values.</param> ///<param name="valueFieldType">The value type.</param> ///<returns>The loaded dictionary.</returns> public IDictionary ExecuteScalarDictionary( IDictionary dic, MapIndex index, NameOrIndexParameter valueField, Type valueFieldType) { if (dic == null) dic = new Hashtable(); if (_prepared) InitParameters(CommandAction.Select); //object nullValue = _mappingSchema.GetNullValue(type); using (var dr = ExecuteReaderInternal()) if (dr.Read()) { var valueIndex = valueField.ByName ? dr.GetOrdinal(valueField.Name) : valueField.Index; var keyIndex = new int[index.Fields.Length]; for (var i = 0; i < keyIndex.Length; i++) keyIndex[i] = index.Fields[i].ByName ? dr.GetOrdinal(index.Fields[i].Name) : index.Fields[i].Index; do { var value = dr[valueIndex]; if (value == null || value.GetType() != valueFieldType) value = value is DBNull ? null : _mappingSchema.ConvertChangeType(value, valueFieldType); var key = new object[keyIndex.Length]; for (var i = 0; i < keyIndex.Length; i++) key[i] = dr[keyIndex[i]]; dic.Add(new CompoundValue(key), value); } while (dr.Read()); } return dic; } ///<summary> /// Executes the query, and returns the dictionary. /// The keys are loaded from columns specified by <paramref name="index"/> and /// values are loaded from a column specified by <paramref name="valueField"/>. /// Other columns are ignored. ///</summary> ///<param name="index">The <see cref="MapIndex"/> of the key columns.</param> ///<param name="valueField">The column name/index to load values.</param> ///<param name="valueFieldType">The value type.</param> ///<returns>The loaded dictionary.</returns> public Hashtable ExecuteScalarDictionary( MapIndex index, NameOrIndexParameter valueField, Type valueFieldType) { var table = new Hashtable(); ExecuteScalarDictionary(table, index, valueField, valueFieldType); return table; } ///<summary> /// Executes the query, and returns the dictionary. /// The keys are loaded from columns specified by <paramref name="index"/> and /// values are loaded from a column specified by <paramref name="valueField"/>. /// Other columns are ignored. ///</summary> ///<typeparam name="T">The value type.</typeparam> ///<param name="dic">The dictionary to add values.</param> ///<param name="index">The <see cref="MapIndex"/> of the key columns.</param> ///<param name="valueField">The column name/index to load values.</param> ///<returns>The loaded dictionary.</returns> public IDictionary<CompoundValue,T> ExecuteScalarDictionary<T>( IDictionary<CompoundValue, T> dic, MapIndex index, NameOrIndexParameter valueField) { if (dic == null) dic = new Dictionary<CompoundValue, T>(); if (_prepared) InitParameters(CommandAction.Select); //object nullValue = _mappingSchema.GetNullValue(type); var valueFieldType = typeof(T); using (var dr = ExecuteReaderInternal()) if (dr.Read()) { var valueIndex = valueField.ByName ? dr.GetOrdinal(valueField.Name) : valueField.Index; var keyIndex = new int[index.Fields.Length]; for (var i = 0; i < keyIndex.Length; i++) keyIndex[i] = index.Fields[i].ByName ? dr.GetOrdinal(index.Fields[i].Name) : index.Fields[i].Index; do { var value = dr[valueIndex]; if (value == null || value.GetType() != valueFieldType) value = value is DBNull ? null : _mappingSchema.ConvertChangeType(value, valueFieldType); var key = new object[keyIndex.Length]; for (var i = 0; i < keyIndex.Length; i++) key[i] = dr[keyIndex[i]]; dic.Add(new CompoundValue(key), (T) value); } while (dr.Read()); } return dic; } ///<summary> /// Executes the query, and returns the dictionary. /// The keys are loaded from columns specified by <paramref name="index"/> and /// values are loaded from a column specified by <paramref name="valueField"/>. /// Other columns are ignored. ///</summary> ///<typeparam name="T">The value type.</typeparam> ///<param name="index">The <see cref="MapIndex"/> of the key columns.</param> ///<param name="valueField">The column name/index to load values.</param> ///<returns>The loaded dictionary.</returns> public Dictionary<CompoundValue,T> ExecuteScalarDictionary<T>( MapIndex index, NameOrIndexParameter valueField) { var dic = new Dictionary<CompoundValue,T>(); ExecuteScalarDictionary(dic, index, valueField); return dic; } #endregion #region ExecuteReader /// <summary> /// Executes the command and builds an <see cref="IDataReader"/>. /// </summary> /// <returns>An instance of the <see cref="IDataReader"/> class.</returns> public IDataReader ExecuteReader() { if (_prepared) InitParameters(CommandAction.Select); return ExecuteReaderInternal(); } /// <summary> /// Executes the command and builds an <see cref="IDataReader"/>. /// </summary> /// <param name="commandBehavior">One of the <see cref="CommandBehavior"/> values.</param> /// <returns>An instance of the <see cref="IDataReader"/> class.</returns> public IDataReader ExecuteReader(CommandBehavior commandBehavior) { if (_prepared) InitParameters(CommandAction.Select); return ExecuteReaderInternal(commandBehavior); } #endregion #region ExecuteDataSet /// <summary> /// Executes a SQL statement using the provided parameters. /// </summary> /// <remarks> /// See the <see cref="ExecuteDataSet(NameOrIndexParameter)"/> method /// to find an example. /// </remarks> /// <returns>The <see cref="DataSet"/>.</returns> public DataSet ExecuteDataSet() { return ExecuteDataSet(null, 0, 0, "Table"); } /// <summary> /// Executes a SQL statement using the provided parameters. /// </summary> /// <remarks> /// See the <see cref="ExecuteDataSet(NameOrIndexParameter)"/> method /// to find an example. /// </remarks> /// <param name="dataSet">The input <see cref="DataSet"/> object.</param> /// <returns>The <see cref="DataSet"/>.</returns> public DataSet ExecuteDataSet( DataSet dataSet) { return ExecuteDataSet(dataSet, 0, 0, "Table"); } /// <summary> /// Executes a SQL statement using the provided parameters. /// </summary> /// <remarks> /// See the <see cref="ExecuteDataSet(NameOrIndexParameter)"/> method /// to find an example. /// </remarks> /// <param name="table">The name or index of the populating table.</param> /// <returns>The <see cref="DataSet"/>.</returns> public DataSet ExecuteDataSet( NameOrIndexParameter table) { return ExecuteDataSet(null, 0, 0, table); } /// <summary> /// Executes a SQL statement using the provided parameters. /// </summary> /// <param name="dataSet">The <see cref="DataSet"/> object to populate.</param> /// <param name="table">The name or index of the populating table.</param> /// <returns>The <see cref="DataSet"/>.</returns> public DataSet ExecuteDataSet( DataSet dataSet, NameOrIndexParameter table) { return ExecuteDataSet(dataSet, 0, 0, table); } /// <summary> /// Executes a SQL statement using the provided parameters. /// </summary> /// <param name="dataSet">The <see cref="DataSet"/> object to populate.</param> /// <param name="table">The name or index of the populating table.</param> /// <param name="startRecord">The zero-based record number to start with.</param> /// <param name="maxRecords">The maximum number of records to retrieve.</param> /// <returns>The <see cref="DataSet"/>.</returns> public DataSet ExecuteDataSet( DataSet dataSet, int startRecord, int maxRecords, NameOrIndexParameter table) { if (_prepared) InitParameters(CommandAction.Select); if (dataSet == null) dataSet = new DataSet(); var da = _dataProvider.CreateDataAdapterObject(); ((IDbDataAdapter)da).SelectCommand = SelectCommand; ExecuteOperation(OperationType.Fill, delegate { if (table.ByName) da.Fill(dataSet, startRecord, maxRecords, table.Name); else da.Fill(startRecord, maxRecords, dataSet.Tables[table.Index]); }); return dataSet; } #endregion #region ExecuteDataTable /// <summary> /// Executes a SQL statement using the provided parameters. /// </summary> /// <returns>The <see cref="DataTable"/>.</returns> public DataTable ExecuteDataTable() { return ExecuteDataTable(null); } /// <summary> /// Executes a SQL statement using the provided parameters. /// </summary> /// <param name="dataTable">The <see cref="DataTable"/> object to populate.</param> /// <returns>The <see cref="DataTable"/>.</returns> public DataTable ExecuteDataTable(DataTable dataTable) { if (_prepared) InitParameters(CommandAction.Select); if (dataTable == null) dataTable = new DataTable(); var da = _dataProvider.CreateDataAdapterObject(); ((IDbDataAdapter)da).SelectCommand = SelectCommand; ExecuteOperation(OperationType.Fill, delegate { da.Fill(dataTable); }); return dataTable; } /// <summary>Adds or refreshes rows in a <see cref="System.Data.DataTable"/> /// to match those in the data source starting at the specified record /// and retrieving up to the specified maximum number of records. /// </summary> /// <param name="startRecord">The zero-based record number to start with.</param> /// <param name="maxRecords">The maximum number of records to retrieve.</param> /// <param name="tableList">The <see cref="System.Data.DataTable"/> objects /// to fill from the data source.</param> public void ExecuteDataTables( int startRecord, int maxRecords, params DataTable[] tableList) { if (tableList == null || tableList.Length == 0) return; if (_prepared) InitParameters(CommandAction.Select); var da = _dataProvider.CreateDataAdapterObject(); ((IDbDataAdapter)da).SelectCommand = SelectCommand; ExecuteOperation(OperationType.Fill, delegate { da.Fill(startRecord, maxRecords, tableList); }); } /// <summary>Adds or refreshes rows in a <see cref="System.Data.DataTable"/> /// to match those in the data source starting at the specified record /// and retrieving up to the specified maximum number of records. /// </summary> /// <param name="tableList">The <see cref="System.Data.DataTable"/> objects /// to fill from the data source.</param> public void ExecuteDataTables(params DataTable[] tableList) { ExecuteDataTables(0, 0, tableList); } #endregion #region ExecuteObject /// <summary> /// Executes a SQL statement and maps resultset to an object. /// </summary> /// <param name="entity">An object to populate.</param> /// <param name="type">The System.Type of the object.</param> /// <param name="parameters">Additional parameters passed to object constructor through <see cref="InitContext"/>.</param> /// <returns>A business object.</returns> private object ExecuteObjectInternal(object entity, Type type, object[] parameters) { if (_prepared) InitParameters(CommandAction.Select); using (var dr = ExecuteReaderInternal(/*CommandBehavior.SingleRow*/)) // Sybase provider does not support this flag. return ExecuteOperation(OperationType.Read, () => { while (dr.Read()) return entity == null ? _mappingSchema.MapDataReaderToObject(dr, type, parameters) : _mappingSchema.MapDataReaderToObject(dr, entity, parameters); return null; }); } /// <summary> /// Executes a SQL statement and maps resultset to an object. /// </summary> /// <param name="entity">An object to populate.</param> /// <returns>A business object.</returns> public object ExecuteObject(object entity) { if (null == entity) throw new ArgumentNullException("entity"); return ExecuteObjectInternal(entity, entity.GetType(), null); } /// <summary> /// Executes a SQL statement and maps resultset to an object. /// </summary> /// <param name="entity">An object to populate.</param> /// <param name="parameters">Additional parameters passed to object constructor through <see cref="InitContext"/>.</param> /// <returns>A business object.</returns> public object ExecuteObject(object entity, params object[] parameters) { if (null == entity) throw new ArgumentNullException("entity"); return ExecuteObjectInternal(entity, entity.GetType(), parameters); } /// <summary> /// Executes a SQL statement and maps resultset to an object. /// </summary> /// <param name="type">Type of an object.</param> /// <returns>A business object.</returns> public object ExecuteObject(Type type) { return ExecuteObjectInternal(null, type, null); } /// <summary> /// Executes a SQL statement and maps resultset to an object. /// </summary> /// <param name="type">Type of an object.</param> /// <param name="parameters">Additional parameters passed to object constructor through <see cref="InitContext"/>.</param> /// <returns>A business object.</returns> public object ExecuteObject(Type type, params object[] parameters) { return ExecuteObjectInternal(null, type, parameters); } /// <summary> /// Executes a SQL statement and maps resultset to an object. /// </summary> /// <typeparam name="T">Type of an object.</typeparam> /// <returns>A business object.</returns> public T ExecuteObject<T>() { return (T)ExecuteObjectInternal(null, typeof(T), null); } /// <summary> /// Executes a SQL statement and maps resultset to an object. /// </summary> /// <typeparam name="T">Type of an object.</typeparam> /// <param name="parameters">Additional parameters passed to object constructor through <see cref="InitContext"/>.</param> /// <returns>A business object.</returns> public T ExecuteObject<T>(params object[] parameters) { return (T)ExecuteObjectInternal(null, typeof(T), parameters); } #endregion #region ExecuteList private IList ExecuteListInternal(IList list, Type type, params object[] parameters) { if (list == null) list = new ArrayList(); if (_prepared) InitParameters(CommandAction.Select); using (var dr = ExecuteReaderInternal()) //wrap this too, because of PostgreSQL lazy query execution return ExecuteOperation(OperationType.Fill, () => _mappingSchema.MapDataReaderToList(dr, list, type, parameters)); } private void ExecuteListInternal<T>(IList<T> list, params object[] parameters) { if (list == null) list = new List<T>(); if (_prepared) InitParameters(CommandAction.Select); using (var dr = ExecuteReaderInternal()) ExecuteOperation(OperationType.Fill, () => _mappingSchema.MapDataReaderToList(dr, list, parameters)); } /// <summary> /// Executes the query, and returns an array of business entities using the provided parameters. /// </summary> /// <param name="type">Type of the business object.</param> /// <returns>An array of business objects.</returns> public ArrayList ExecuteList(Type type) { var arrayList = new ArrayList(); ExecuteListInternal(arrayList, type, null); return arrayList; } /// <summary> /// Executes the query, and returns an array of business entities. /// </summary> /// <typeparam name="T">Type of an object.</typeparam> /// <returns>Populated list of mapped business objects.</returns> public List<T> ExecuteList<T>() { var list = new List<T>(); ExecuteListInternal<T>(list, null); return list; } /// <summary> /// Executes the query, and returns an array of business entities using the provided parameters. /// </summary> /// <param name="type">Type of the business object.</param> /// <param name="parameters">Additional parameters passed to object constructor through <see cref="InitContext"/>.</param> /// <returns>An array of business objects.</returns> public ArrayList ExecuteList(Type type, params object[] parameters) { var arrayList = new ArrayList(); ExecuteListInternal(arrayList, type, parameters); return arrayList; } /// <summary> /// Executes the query, and returns an array of business entities. /// </summary> /// <typeparam name="T">Type of an object.</typeparam> /// <param name="parameters">Additional parameters passed to object constructor through <see cref="InitContext"/>.</param> /// <returns>Populated list of mapped business objects.</returns> public List<T> ExecuteList<T>(params object[] parameters) { var list = new List<T>(); ExecuteListInternal(list, parameters); return list; } /// <summary> /// Executes the query, and returns an array of business entities. /// </summary> /// <param name="list">The list of mapped business objects to populate.</param> /// <param name="type">Type of an object.</param> /// <returns>Populated list of mapped business objects.</returns> public IList ExecuteList(IList list, Type type) { return ExecuteListInternal(list, type, null); } /// <summary> /// Executes the query, and returns an array of business entities. /// </summary> /// <typeparam name="T">Type of an object.</typeparam> /// <param name="list">The list of mapped business objects to populate.</param> /// <returns>Populated list of mapped business objects.</returns> public IList<T> ExecuteList<T>(IList<T> list) { ExecuteListInternal(list, null); return list; } /// <summary> /// Executes the query, and returns an array of business entities. /// </summary> /// <param name="list">The list of mapped business objects to populate.</param> /// <param name="type">Type of an object.</param> /// <param name="parameters">Additional parameters passed to object constructor through <see cref="InitContext"/>.</param> /// <returns>Populated list of mapped business objects.</returns> public IList ExecuteList(IList list, Type type, params object[] parameters) { return ExecuteListInternal(list, type, parameters); } /// <summary> /// Executes the query, and returns an array of business entities. /// </summary> /// <typeparam name="T">Type of an object.</typeparam> /// <param name="list">The list of mapped business objects to populate.</param> /// <param name="parameters">Additional parameters passed to object constructor through <see cref="InitContext"/>.</param> /// <returns>Populated list of mapped business objects.</returns> public IList<T> ExecuteList<T>(IList<T> list, params object[] parameters) { ExecuteListInternal(list, parameters); return list; } /// <summary> /// Executes the query, and returns an array of business entities. /// </summary> /// <typeparam name="TList">Type of a list.</typeparam> /// <typeparam name="T">Type of an object.</typeparam> /// <param name="list">The list of mapped business objects to populate.</param> /// <param name="parameters">Additional parameters passed to object constructor through <see cref="InitContext"/>.</param> /// <returns>Populated list of mapped business objects.</returns> public TList ExecuteList<TList,T>(TList list, params object[] parameters) where TList : IList<T> { ExecuteListInternal(list, typeof(T), parameters); return list; } /// <summary> /// Executes the query, and returns an array of business entities. /// </summary> /// <typeparam name="TList">Type of a list.</typeparam> /// <typeparam name="T">Type of an object.</typeparam> /// <param name="parameters">Additional parameters passed to object constructor through <see cref="InitContext"/>.</param> /// <returns>Populated list of mapped business objects.</returns> public TList ExecuteList<TList,T>(params object[] parameters) where TList : IList<T>, new() { var list = new TList(); ExecuteListInternal(list, typeof(T), parameters); return list; } #endregion #region ExecuteDictionary /// <summary> /// Executes the query, and returns the <see cref="Hashtable"/> of business entities /// using the provided parameters. /// </summary> /// <include file="Examples.xml" path='examples/db[@name="ExecuteDictionary(string,Type)"]/*' /> /// <param name="keyField">The field name or index that is used as a key to populate <see cref="Hashtable"/>.</param> /// <param name="keyFieldType">Business object type.</param> /// <param name="parameters">Any additional parameters passed to the constructor with <see cref="InitContext"/> parameter.</param> /// <returns>An instance of the <see cref="Hashtable"/> class.</returns> public Hashtable ExecuteDictionary( NameOrIndexParameter keyField, Type keyFieldType, params object[] parameters) { var hash = new Hashtable(); ExecuteDictionary(hash, keyField, keyFieldType, parameters); return hash; } /// <summary> /// Executes the query, and returns the <see cref="Hashtable"/> of business entities. /// </summary> /// <include file="Examples.xml" path='examples/db[@name="ExecuteDictionary(Hashtable,string,Type)"]/*' /> /// <param name="dictionary">A dictionary of mapped business objects to populate.</param> /// <param name="keyField">The field name or index that is used as a key to populate <see cref="IDictionary"/>.</param> /// <param name="type">Business object type.</param> /// <param name="parameters">Any additional parameters passed to the constructor with <see cref="InitContext"/> parameter.</param> /// <returns>An instance of the <see cref="IDictionary"/>.</returns> public IDictionary ExecuteDictionary( IDictionary dictionary, NameOrIndexParameter keyField, Type type, params object[] parameters) { if (dictionary == null) dictionary = new Hashtable(); if (_prepared) InitParameters(CommandAction.Select); using (var dr = ExecuteReaderInternal()) return _mappingSchema.MapDataReaderToDictionary(dr, dictionary, keyField, type, parameters); } /// <summary> /// Executes the query, and returns a dictionary of business entities. /// </summary> /// <typeparam name="TKey">Key's type.</typeparam> /// <typeparam name="TValue">Value's type.</typeparam> /// <param name="keyField">The field name or index that is used as a key to populate the dictionary.</param> /// <param name="parameters">Any additional parameters passed to the constructor with <see cref="InitContext"/> parameter.</param> /// <returns>An instance of the dictionary.</returns> public Dictionary<TKey, TValue> ExecuteDictionary<TKey, TValue>( NameOrIndexParameter keyField, params object[] parameters) { var dictionary = new Dictionary<TKey, TValue>(); ExecuteDictionary<TKey, TValue>(dictionary, keyField, typeof(TValue), parameters); return dictionary; } /// <summary> /// Executes the query, and returns the <see cref="Hashtable"/> of business entities. /// </summary> /// <param name="dictionary">A dictionary of mapped business objects to populate.</param> /// <param name="keyField">The field name or index that is used as a key to populate <see cref="IDictionary"/>.</param> /// <param name="parameters">Any additional parameters passed to the constructor with <see cref="InitContext"/> parameter.</param> /// <returns>An instance of the <see cref="IDictionary"/>.</returns> public IDictionary<TKey, TValue> ExecuteDictionary<TKey, TValue>( IDictionary<TKey, TValue> dictionary, NameOrIndexParameter keyField, params object[] parameters) { return ExecuteDictionary(dictionary, keyField, typeof(TValue), parameters); } /// <summary> /// Executes the query, and returns the <see cref="Hashtable"/> of business entities. /// </summary> /// <param name="dictionary">A dictionary of mapped business objects to populate.</param> /// <param name="keyField">The field name or index that is used as a key to populate <see cref="IDictionary"/>.</param> /// <param name="destObjectType">Business object type.</param> /// <param name="parameters">Any additional parameters passed to the constructor with <see cref="InitContext"/> parameter.</param> /// <returns>An instance of the <see cref="IDictionary"/>.</returns> public IDictionary<TKey, TValue> ExecuteDictionary<TKey, TValue>( IDictionary<TKey, TValue> dictionary, NameOrIndexParameter keyField, Type destObjectType, params object[] parameters) { if (dictionary == null) dictionary = new Dictionary<TKey, TValue>(); if (_prepared) InitParameters(CommandAction.Select); using (var dr = ExecuteReaderInternal()) return _mappingSchema.MapDataReaderToDictionary( dr, dictionary, keyField, destObjectType, parameters); } #endregion #region ExecuteDictionary (Index) /// <summary> /// Executes the query, and returns the <see cref="Hashtable"/> of business entities /// using the provided parameters. /// </summary> /// <include file="Examples.xml" path='examples/db[@name="ExecuteDictionary(string,Type)"]/*' /> /// <param name="index">Dictionary key fields.</param> /// <param name="type">Business object type.</param> /// <param name="parameters">Any additional parameters passed to the constructor with <see cref="InitContext"/> parameter.</param> /// <returns>An instance of the <see cref="Hashtable"/> class.</returns> public Hashtable ExecuteDictionary( MapIndex index, Type type, params object[] parameters) { var hash = new Hashtable(); ExecuteDictionary(hash, index, type, parameters); return hash; } /// <summary> /// Executes the query, and returns the <see cref="Hashtable"/> of business entities. /// </summary> /// <include file="Examples.xml" path='examples/db[@name="ExecuteDictionary(Hashtable,string,Type)"]/*' /> /// <param name="dictionary">A dictionary of mapped business objects to populate.</param> /// <param name="index">Dictionary key fields.</param> /// <param name="type">Business object type.</param> /// <param name="parameters">Any additional parameters passed to the constructor with <see cref="InitContext"/> parameter.</param> /// <returns>An instance of the <see cref="IDictionary"/>.</returns> public IDictionary ExecuteDictionary( IDictionary dictionary, MapIndex index, Type type, params object[] parameters) { if (dictionary == null) dictionary = new Hashtable(); if (_prepared) InitParameters(CommandAction.Select); using (var dr = ExecuteReaderInternal()) return _mappingSchema.MapDataReaderToDictionary(dr, dictionary, index, type, parameters); } /// <summary> /// Executes the query, and returns a dictionary of business entities. /// </summary> /// <typeparam name="TValue">Value's type.</typeparam> /// <param name="index">Dictionary key fields.</param> /// <param name="parameters">Any additional parameters passed to the constructor with <see cref="InitContext"/> parameter.</param> /// <returns>An instance of the dictionary.</returns> public Dictionary<CompoundValue, TValue> ExecuteDictionary<TValue>( MapIndex index, params object[] parameters) { var dictionary = new Dictionary<CompoundValue, TValue>(); ExecuteDictionary<TValue>(dictionary, index, typeof(TValue), parameters); return dictionary; } /// <summary> /// Executes the query, and returns a dictionary of business entities. /// </summary> /// <typeparam name="TValue">Value's type.</typeparam> /// <param name="dictionary">A dictionary of mapped business objects to populate.</param> /// <param name="index">Dictionary key fields.</param> /// <param name="parameters">Any additional parameters passed to the constructor with <see cref="InitContext"/> parameter.</param> /// <returns>An instance of the dictionary.</returns> public IDictionary<CompoundValue, TValue> ExecuteDictionary<TValue>( IDictionary<CompoundValue, TValue> dictionary, MapIndex index, params object[] parameters) { return ExecuteDictionary(dictionary, index, typeof(TValue), parameters); } /// <summary> /// Executes the query, and returns a dictionary of business entities. /// </summary> /// <typeparam name="TValue">Value's type.</typeparam> /// <param name="dictionary">A dictionary of mapped business objects to populate.</param> /// <param name="index">Dictionary key fields.</param> /// <param name="destObjectType">Business object type.</param> /// <param name="parameters">Any additional parameters passed to the constructor with <see cref="InitContext"/> parameter.</param> /// <returns>An instance of the dictionary.</returns> public IDictionary<CompoundValue, TValue> ExecuteDictionary<TValue>( IDictionary<CompoundValue, TValue> dictionary, MapIndex index, Type destObjectType, params object[] parameters) { if (dictionary == null) dictionary = new Dictionary<CompoundValue, TValue>(); if (_prepared) InitParameters(CommandAction.Select); using (var dr = ExecuteReaderInternal()) return _mappingSchema.MapDataReaderToDictionary( dr, dictionary, index, destObjectType, parameters); } #endregion #region ExecuteResultSet /// <summary> /// Executes the query, and returns multiple results. /// </summary> /// <param name="resultSets">Array of <see cref="MapResultSet"/> to populate.</param> /// <returns>The populated <see cref="MapResultSet"/>.</returns> public MapResultSet[] ExecuteResultSet(params MapResultSet[] resultSets) { if (_prepared) InitParameters(CommandAction.Select); using (var dr = ExecuteReaderInternal()) _mappingSchema.MapDataReaderToResultSet(dr, resultSets); return resultSets; } /// <summary> /// Executes the query, and returns multiple results. /// </summary> /// <param name="masterType">The type of the master business object.</param> /// <param name="nextResults">Array of <see cref="MapNextResult"/> to populate.</param> /// <returns>The populated <see cref="MapResultSet"/>.</returns> public MapResultSet[] ExecuteResultSet( Type masterType, params MapNextResult[] nextResults) { return ExecuteResultSet(_mappingSchema.ConvertToResultSet(masterType, nextResults)); } /// <summary> /// Executes the query, and returns multiple results. /// </summary> /// <typeparam name="T">The type of the master business object.</typeparam> /// <param name="nextResults">Array of <see cref="MapNextResult"/> to populate.</param> /// <returns>The populated <see cref="MapResultSet"/>.</returns> public MapResultSet[] ExecuteResultSet<T>(params MapNextResult[] nextResults) { return ExecuteResultSet(_mappingSchema.ConvertToResultSet(typeof(T), nextResults)); } #endregion #region Update private DbDataAdapter CreateDataAdapter() { var da = _dataProvider.CreateDataAdapterObject(); if (_insertCommand != null) ((IDbDataAdapter)da).InsertCommand = InsertCommand; if (_updateCommand != null) ((IDbDataAdapter)da).UpdateCommand = UpdateCommand; if (_deleteCommand != null) ((IDbDataAdapter)da).DeleteCommand = DeleteCommand; return da; } /// <summary> /// Calls the corresponding INSERT, UPDATE, or DELETE statements for each inserted, updated, or /// deleted row in the specified <see cref="DataSet"/>. /// </summary> /// <param name="dataSet">The <see cref="DataSet"/> used to update the data source.</param> /// <returns>The number of rows successfully updated from the <see cref="DataSet"/>.</returns> public int Update(DataSet dataSet) { return Update(dataSet, "Table"); } /// <summary> /// Calls the corresponding INSERT, UPDATE, or DELETE statements for each inserted, updated, or /// deleted row in the <see cref="DataSet"/> with the specified <see cref="DataTable"/> name. /// </summary> /// <param name="dataSet">The <see cref="DataSet"/> used to update the data source.</param> /// <param name="table">The name or index of the source table to use for table mapping.</param> /// <returns>The number of rows successfully updated from the <see cref="DataSet"/>.</returns> public int Update( DataSet dataSet, NameOrIndexParameter table) { if (dataSet == null) throw new ArgumentNullException( "dataSet", Resources.DbManager_CannotUpdateNullDataset); var da = CreateDataAdapter(); return ExecuteOperation( OperationType.Update, () => (table.ByName) ? da.Update(dataSet, table.Name) : da.Update(dataSet.Tables[table.Index])); } /// <summary> /// Calls the corresponding INSERT, UPDATE, or DELETE statements for /// each inserted, updated, or deleted row in the specified /// <see cref="DataTable"/>. /// </summary> /// <param name="dataTable">The name or index of the source table to /// use for table mapping.</param> /// <returns>The number of rows successfully updated from the /// <see cref="DataTable"/>.</returns> public int Update(DataTable dataTable) { if (dataTable == null) throw new ArgumentNullException( "dataTable", Resources.DbManager_CannotUpdateNullDataTable); return ExecuteOperation( OperationType.Update, () => CreateDataAdapter().Update(dataTable)); } #endregion #region ExecuteOperation private void ExecuteOperation(OperationType operationType, Action operation) { try { OnBeforeOperation(operationType); operation(); OnAfterOperation (operationType); } catch (Exception ex) { HandleOperationException(operationType, ex); throw; } } private T ExecuteOperation<T>(OperationType operationType, Func<T> operation) { var res = default(T); try { OnBeforeOperation(operationType); res = operation(); OnAfterOperation (operationType); } catch (Exception ex) { if (res is IDisposable) ((IDisposable)res).Dispose(); HandleOperationException(operationType, ex); throw; } return res; } private void HandleOperationException(OperationType op, Exception ex) { var dex = new DataException(this, ex); if (TraceSwitch.TraceError) WriteTraceLine(string.Format("Operation '{0}' throws exception '{1}'", op, dex), TraceSwitch.DisplayName); OnOperationException(op, dex); } #endregion #region IDisposable interface /// <summary> /// Releases the unmanaged resources used by the <see cref="DbManager"/> and /// optionally releases the managed resources. /// </summary> /// <remarks> /// This method is called by the public <see cref="IDisposable.Dispose()"/> method /// and the Finalize method. /// </remarks> /// <param name="disposing"><b>true</b> to release both managed and unmanaged resources; <b>false</b> to release only unmanaged resources.</param> protected override void Dispose(bool disposing) { if (disposing) Close(); base.Dispose(disposing); } #endregion } }