X Tutup
// created on 09/07/2003 at 20:20 // Npgsql.NpgsqlParameterCollection.cs // // Author: // Brar Piening (brar@gmx.de) // // Rewritten from the scratch to derive from MarshalByRefObject instead of ArrayList. // Recycled some parts of the original NpgsqlParameterCollection.cs // by Francisco Jr. (fxjrlists@yahoo.com.br) // // Copyright (C) 2002 The Npgsql Development Team // npgsql-general@gborg.postgresql.org // http://gborg.postgresql.org/project/npgsql/projdisplay.php // // Permission to use, copy, modify, and distribute this software and its // documentation for any purpose, without fee, and without a written // agreement is hereby granted, provided that the above copyright notice // and this paragraph and the following two paragraphs appear in all copies. // // IN NO EVENT SHALL THE NPGSQL DEVELOPMENT TEAM BE LIABLE TO ANY PARTY // FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, // INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS // DOCUMENTATION, EVEN IF THE NPGSQL DEVELOPMENT TEAM HAS BEEN ADVISED OF // THE POSSIBILITY OF SUCH DAMAGE. // // THE NPGSQL DEVELOPMENT TEAM SPECIFICALLY DISCLAIMS ANY WARRANTIES, // INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY // AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS // ON AN "AS IS" BASIS, AND THE NPGSQL DEVELOPMENT TEAM HAS NO OBLIGATIONS // TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data.Common; using System.Reflection; using System.Resources; using NpgsqlTypes; #if WITHDESIGN #endif namespace Npgsql { /// /// Represents a collection of parameters relevant to a NpgsqlCommand /// as well as their respective mappings to columns in a DataSet. /// This class cannot be inherited. /// #if WITHDESIGN [ListBindable(false)] [Editor(typeof(NpgsqlParametersEditor), typeof(System.Drawing.Design.UITypeEditor))] #endif public sealed class NpgsqlParameterCollection : DbParameterCollection { private readonly List InternalList = new List(); // Dictionary lookups for GetValue to improve performance private Dictionary lookup; private Dictionary lookupIgnoreCase; // Logging related value private static readonly String CLASSNAME = MethodBase.GetCurrentMethod().DeclaringType.Name; // Our resource manager private static readonly ResourceManager resman = new ResourceManager(MethodBase.GetCurrentMethod().DeclaringType); /// /// Initializes a new instance of the NpgsqlParameterCollection class. /// internal NpgsqlParameterCollection() { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME); InvalidateHashLookups(); } /// /// Invalidate the hash lookup tables. This should be done any time a change /// may throw the lookups out of sync with the list. /// internal void InvalidateHashLookups() { lookup = null; lookupIgnoreCase = null; } #region NpgsqlParameterCollection Member /// /// Gets the NpgsqlParameter with the specified name. /// /// The name of the NpgsqlParameter to retrieve. /// The NpgsqlParameter with the specified name, or a null reference if the parameter is not found. #if WITHDESIGN [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] #endif public new NpgsqlParameter this[string parameterName] { get { NpgsqlEventLog.LogIndexerGet(LogLevel.Debug, CLASSNAME, parameterName); int index = IndexOf(parameterName); if (index == -1) { throw new IndexOutOfRangeException("Parameter not found"); } return this.InternalList[index]; } set { NpgsqlEventLog.LogIndexerSet(LogLevel.Debug, CLASSNAME, parameterName, value); int index = IndexOf(parameterName); if (index == -1) { throw new IndexOutOfRangeException("Parameter not found"); } NpgsqlParameter oldValue = this.InternalList[index]; if (value.CleanName != oldValue.CleanName) { InvalidateHashLookups(); } this.InternalList[index] = value; } } /// /// Gets the NpgsqlParameter at the specified index. /// /// The zero-based index of the NpgsqlParameter to retrieve. /// The NpgsqlParameter at the specified index. #if WITHDESIGN [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] #endif public new NpgsqlParameter this[int index] { get { NpgsqlEventLog.LogIndexerGet(LogLevel.Debug, CLASSNAME, index); return this.InternalList[index]; } set { NpgsqlEventLog.LogIndexerSet(LogLevel.Debug, CLASSNAME, index, value); NpgsqlParameter oldValue = this.InternalList[index]; if (oldValue == value) { // Reasigning the same value is a non-op. return; } if (value.Collection != null) { throw new InvalidOperationException("The parameter already belongs to a collection"); } if (value.CleanName != oldValue.CleanName) { InvalidateHashLookups(); } this.InternalList[index] = value; value.Collection = this; oldValue.Collection = null; } } /// /// Adds the specified NpgsqlParameter object to the NpgsqlParameterCollection. /// /// The NpgsqlParameter to add to the collection. /// The index of the new NpgsqlParameter object. public NpgsqlParameter Add(NpgsqlParameter value) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Add", value); // Do not allow parameters without name. if (value.Collection != null) { throw new InvalidOperationException("The parameter already belongs to a collection"); } this.InternalList.Add(value); value.Collection = this; this.InvalidateHashLookups(); // Check if there is a name. If not, add a name based in the index of parameter. if (value.ParameterName.Trim() == String.Empty || (value.ParameterName.Length == 1 && value.ParameterName[0] == ':')) { value.ParameterName = ":" + "Parameter" + (IndexOf(value) + 1); } return value; } /// /// Obsolete. Use AddWithValue instead. /// /// /// Use caution when using this overload of the /// Add method to specify integer parameter values. /// Because this overload takes a value of type Object, /// you must convert the integral value to an Object /// type when the value is zero, as the following C# example demonstrates. /// parameters.Add(":pname", Convert.ToInt32(0)); /// If you do not perform this conversion, the compiler will assume you /// are attempting to call the NpgsqlParameterCollection.Add(string, DbType) overload. /// [Obsolete("Do not call this method. Use AddWithValue instead.")] public NpgsqlParameter Add(string parameterName, object value) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Add", parameterName, value); return this.AddWithValue(parameterName, value); } /// /// Adds a NpgsqlParameter to the NpgsqlParameterCollection given the specified parameter name and value. /// /// The name of the NpgsqlParameter. /// The Value of the NpgsqlParameter to add to the collection. /// The paramater that was added. public NpgsqlParameter AddWithValue(string parameterName, object value) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "AddWithValue", parameterName, value); return this.Add(new NpgsqlParameter(parameterName, value)); } /// /// Adds a NpgsqlParameter to the NpgsqlParameterCollection given the specified parameter name and value. /// /// The name of the NpgsqlParameter. /// The Value of the NpgsqlParameter to add to the collection. /// One of the NpgsqlDbType values. /// The paramater that was added. public NpgsqlParameter AddWithValue(string parameterName, NpgsqlDbType parameterType, object value) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "AddWithValue", parameterName, parameterType, value); NpgsqlParameter param = new NpgsqlParameter(parameterName, parameterType); param.Value = value; return this.Add(param); } /// /// Adds a NpgsqlParameter to the NpgsqlParameterCollection given the specified parameter name and value. /// /// The name of the NpgsqlParameter. /// The Value of the NpgsqlParameter to add to the collection. /// One of the NpgsqlDbType values. /// The length of the column. /// The paramater that was added. public NpgsqlParameter AddWithValue(string parameterName, NpgsqlDbType parameterType, int size, object value) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "AddWithValue", parameterName, parameterType, size, value); NpgsqlParameter param = new NpgsqlParameter(parameterName, parameterType, size); param.Value = value; return this.Add(param); } /// /// Adds a NpgsqlParameter to the NpgsqlParameterCollection given the specified parameter name and value. /// /// The name of the NpgsqlParameter. /// The Value of the NpgsqlParameter to add to the collection. /// One of the NpgsqlDbType values. /// The length of the column. /// The name of the source column. /// The paramater that was added. public NpgsqlParameter AddWithValue(string parameterName, NpgsqlDbType parameterType, int size, string sourceColumn, object value) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "AddWithValue", parameterName, parameterType, size, sourceColumn, value); NpgsqlParameter param = new NpgsqlParameter(parameterName, parameterType, size, sourceColumn); param.Value = value; return this.Add(param); } /// /// Adds a NpgsqlParameter to the NpgsqlParameterCollection given the parameter name and the data type. /// /// The name of the parameter. /// One of the DbType values. /// The index of the new NpgsqlParameter object. public NpgsqlParameter Add(string parameterName, NpgsqlDbType parameterType) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Add", parameterName, parameterType); return this.Add(new NpgsqlParameter(parameterName, parameterType)); } /// /// Adds a NpgsqlParameter to the NpgsqlParameterCollection with the parameter name, the data type, and the column length. /// /// The name of the parameter. /// One of the DbType values. /// The length of the column. /// The index of the new NpgsqlParameter object. public NpgsqlParameter Add(string parameterName, NpgsqlDbType parameterType, int size) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Add", parameterName, parameterType, size); return this.Add(new NpgsqlParameter(parameterName, parameterType, size)); } /// /// Adds a NpgsqlParameter to the NpgsqlParameterCollection with the parameter name, the data type, the column length, and the source column name. /// /// The name of the parameter. /// One of the DbType values. /// The length of the column. /// The name of the source column. /// The index of the new NpgsqlParameter object. public NpgsqlParameter Add(string parameterName, NpgsqlDbType parameterType, int size, string sourceColumn) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Add", parameterName, parameterType, size, sourceColumn); return this.Add(new NpgsqlParameter(parameterName, parameterType, size, sourceColumn)); } #endregion #region IDataParameterCollection Member /// /// Removes the specified NpgsqlParameter from the collection using the parameter name. /// /// The name of the NpgsqlParameter object to retrieve. public override void RemoveAt(string parameterName) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "RemoveAt", parameterName); int index = IndexOf(parameterName); NpgsqlParameter existing = InternalList[index]; this.InternalList.RemoveAt(index); existing.Collection = null; this.InvalidateHashLookups(); } /// /// Gets a value indicating whether a NpgsqlParameter with the specified parameter name exists in the collection. /// /// The name of the NpgsqlParameter object to find. /// true if the collection contains the parameter; otherwise, false. public override bool Contains(string parameterName) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Contains", parameterName); return (IndexOf(parameterName) != -1); } /// /// Gets the location of the NpgsqlParameter in the collection with a specific parameter name. /// /// The name of the NpgsqlParameter object to find. /// The zero-based location of the NpgsqlParameter in the collection. public override int IndexOf(string parameterName) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IndexOf", parameterName); int retIndex; int scanIndex; if ((parameterName[0] == ':') || (parameterName[0] == '@')) { parameterName = parameterName.Remove(0, 1); } // Using a dictionary is much faster for 5 or more items if (this.InternalList.Count >= 5) { if (this.lookup == null) { this.lookup = new Dictionary(); for (scanIndex = 0 ; scanIndex < this.InternalList.Count ; scanIndex++) { var item = this.InternalList[scanIndex]; // Store only the first of each distinct value if (! this.lookup.ContainsKey(item.CleanName)) { this.lookup.Add(item.CleanName, scanIndex); } } } // Try to access the case sensitive parameter name first if (this.lookup.TryGetValue(parameterName, out retIndex)) { return retIndex; } // Case sensitive lookup failed, generate a case insensitive lookup if (this.lookupIgnoreCase == null) { this.lookupIgnoreCase = new Dictionary(StringComparer.InvariantCultureIgnoreCase); for (scanIndex = 0 ; scanIndex < this.InternalList.Count ; scanIndex++) { var item = this.InternalList[scanIndex]; // Store only the first of each distinct value if (! this.lookupIgnoreCase.ContainsKey(item.CleanName)) { this.lookupIgnoreCase.Add(item.CleanName, scanIndex); } } } // Then try to access the case insensitive parameter name if (this.lookupIgnoreCase.TryGetValue(parameterName, out retIndex)) { return retIndex; } return -1; } retIndex = -1; // Scan until a case insensitive match is found, and save its index for possible return. // Items that don't match loosely cannot possibly match exactly. for (scanIndex = 0 ; scanIndex < this.InternalList.Count ; scanIndex++) { var item = this.InternalList[scanIndex]; if (string.Compare(parameterName, item.CleanName, StringComparison.InvariantCultureIgnoreCase) == 0) { retIndex = scanIndex; break; } } // Then continue the scan until a case sensitive match is found, and return it. // If a case insensitive match was found, it will be re-checked for an exact match. for ( ; scanIndex < this.InternalList.Count ; scanIndex++) { var item = this.InternalList[scanIndex]; if(item.CleanName == parameterName) { return scanIndex; } } // If a case insensitive match was found, it will be returned here. return retIndex; } #endregion #region IList Member /// /// Report whether the collection is read only. Always false. /// public override bool IsReadOnly { get { NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "IsReadOnly"); return false; } } /// /// Removes the specified NpgsqlParameter from the collection using a specific index. /// /// The zero-based index of the parameter. public override void RemoveAt(int index) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "RemoveAt", index); if (InternalList.Count - 1 < index) { throw new IndexOutOfRangeException(); } InternalList[index].Collection = null; InternalList.RemoveAt(index); InvalidateHashLookups(); } /// /// Inserts a NpgsqlParameter into the collection at the specified index. /// /// The zero-based index where the parameter is to be inserted within the collection. /// The NpgsqlParameter to add to the collection. public override void Insert(int index, object oValue) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Insert", index, oValue); CheckType(oValue); NpgsqlParameter value = oValue as NpgsqlParameter; if (value.Collection != null) { throw new InvalidOperationException("The parameter already belongs to a collection"); } value.Collection = this; this.InternalList.Insert(index, value); this.InvalidateHashLookups(); } /// /// Removes the specified NpgsqlParameter from the collection. /// /// The name of the NpgsqlParameter to remove from the collection. public void Remove(string parameterName) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Remove", parameterName); int index; index = IndexOf(parameterName); if (index < 0) { throw new InvalidOperationException("No parameter with the specified name exists in the collection"); } this.InternalList[index].Collection = null; this.InternalList.RemoveAt(index); this.InvalidateHashLookups(); } /// /// Removes the specified NpgsqlParameter from the collection. /// /// The NpgsqlParameter to remove from the collection. public override void Remove(object oValue) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Remove", oValue); CheckType(oValue); NpgsqlParameter value = oValue as NpgsqlParameter; if (value.Collection != this) { throw new InvalidOperationException("The item does not belong to this collection"); } value.Collection = null; this.InternalList.Remove(value); this.InvalidateHashLookups(); } /// /// Gets a value indicating whether a NpgsqlParameter exists in the collection. /// /// The value of the NpgsqlParameter object to find. /// true if the collection contains the NpgsqlParameter object; otherwise, false. public override bool Contains(object value) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Contains", value); if (!(value is NpgsqlParameter)) { return false; } return this.InternalList.Contains((NpgsqlParameter) value); } /// /// Gets a value indicating whether a NpgsqlParameter with the specified parameter name exists in the collection. /// /// The name of the NpgsqlParameter object to find. /// A reference to the requested parameter is returned in this out param if it is found in the list. This value is null if the parameter is not found. /// true if the collection contains the parameter and param will contain the parameter; otherwise, false. public bool TryGetValue(string parameterName, out NpgsqlParameter parameter) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "TryGetValue", parameterName); int index = IndexOf(parameterName); if (index != -1) { parameter = InternalList[index]; return true; } else { parameter = null; return false; } } /// /// Removes all items from the collection. /// public override void Clear() { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Clear"); this.InternalList.Clear(); this.InvalidateHashLookups(); } /// /// Gets the location of a NpgsqlParameter in the collection. /// /// The value of the NpgsqlParameter object to find. /// The zero-based index of the NpgsqlParameter object in the collection. public override int IndexOf(object value) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "IndexOf", value); CheckType(value); return this.InternalList.IndexOf((NpgsqlParameter) value); } /// /// Adds the specified NpgsqlParameter object to the NpgsqlParameterCollection. /// /// The NpgsqlParameter to add to the collection. /// The zero-based index of the new NpgsqlParameter object. public override int Add(object value) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Add", value); CheckType(value); this.Add((NpgsqlParameter) value); return Count - 1; } /// /// Report whether the collection is fixed size. Always false. /// public override bool IsFixedSize { get { NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "IsFixedSize"); return false; } } #endregion #region ICollection Member /// /// Report whether the collection is synchronized. /// public override bool IsSynchronized { get { NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "IsSynchronized"); return (InternalList as ICollection).IsSynchronized; } } /// /// Gets the number of NpgsqlParameter objects in the collection. /// /// The number of NpgsqlParameter objects in the collection. #if WITHDESIGN [Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] #endif public override int Count { get { NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "Count"); return this.InternalList.Count; } } /// /// Copies NpgsqlParameter objects from the NpgsqlParameterCollection to the specified array. /// /// An Array to which to copy the NpgsqlParameter objects in the collection. /// The starting index of the array. public override void CopyTo(Array array, int index) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CopyTo", array, index); (InternalList as ICollection).CopyTo(array, index); IRaiseItemChangedEvents x = InternalList as IRaiseItemChangedEvents; } /// /// Sync root. /// public override object SyncRoot { get { NpgsqlEventLog.LogPropertyGet(LogLevel.Debug, CLASSNAME, "SyncRoot"); return (InternalList as ICollection).SyncRoot; } } #endregion #region IEnumerable Member /// /// Returns an enumerator that can iterate through the collection. /// /// An IEnumerator that can be used to iterate through the collection. public override IEnumerator GetEnumerator() { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetEnumerator"); return this.InternalList.GetEnumerator(); } #endregion /// /// Add an Array of parameters to the collection. /// /// Parameters to add. public override void AddRange(Array values) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "AddRange", values); foreach (NpgsqlParameter parameter in values) { Add(parameter); } } /// /// Get parameter. /// /// /// protected override DbParameter GetParameter(string parameterName) { return this[parameterName]; } /// /// Get parameter. /// /// /// protected override DbParameter GetParameter(int index) { return this[index]; } /// /// Set parameter. /// /// /// protected override void SetParameter(string parameterName, DbParameter value) { this[parameterName] = (NpgsqlParameter) value; } /// /// Set parameter. /// /// /// protected override void SetParameter(int index, DbParameter value) { this[index] = (NpgsqlParameter) value; } /// /// In methods taking an object as argument this method is used to verify /// that the argument has the type NpgsqlParameter /// /// The object to verify private void CheckType(object Object) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CheckType", Object); if (!(Object is NpgsqlParameter)) { throw new InvalidCastException( String.Format(resman.GetString("Exception_WrongType"), Object.GetType())); } } /* /// /// In methods taking an array as argument this method is used to verify /// that the argument has the type NpgsqlParameter[] /// /// The array to verify private void CheckType(Array array) { NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "CheckType", array); if (array.GetType() != typeof (NpgsqlParameter[])) { throw new InvalidCastException( String.Format(this.resman.GetString("Exception_WrongType"), array.GetType().ToString())); } } */ /// /// Report the offset within the collection of the given parameter. /// /// Parameter to find. /// Index of the parameter, or -1 if the parameter is not present. public int IndexOf(NpgsqlParameter item) { return InternalList.IndexOf(item); } /// /// Insert the specified parameter into the collection. /// /// Index of the existing parameter before which to insert the new one. /// Parameter to insert. public void Insert(int index, NpgsqlParameter item) { if (item.Collection != null) { throw new Exception("The parameter already belongs to a collection"); } InternalList.Insert(index, item); item.Collection = this; this.InvalidateHashLookups(); } /// /// Report whether the specified parameter is present in the collection. /// /// Parameter to find. /// True if the parameter was found, otherwise false. public bool Contains(NpgsqlParameter item) { return InternalList.Contains(item); } /// /// Remove the specified parameter from the collection. /// /// Parameter to remove. /// True if the parameter was found and removed, otherwise false. public bool Remove(NpgsqlParameter item) { if (InternalList.Remove(item)) { item.Collection = null; this.InvalidateHashLookups(); return true; } return false; } /// /// Convert collection to a System.Array. /// /// Destination array. /// Starting index in destination array. public void CopyTo(NpgsqlParameter[] array, int arrayIndex) { InternalList.CopyTo(array, arrayIndex); } /// /// Convert collection to a System.Array. /// /// NpgsqlParameter[] public NpgsqlParameter[] ToArray() { return InternalList.ToArray(); } } }
X Tutup