| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411 |
- //
- // System.Data.ConstraintCollection.cs
- //
- // Author:
- // Franklin Wise <[email protected]>
- // Daniel Morgan
- //
- // (C) Ximian, Inc. 2002
- // (C) 2002 Franklin Wise
- // (C) 2002 Daniel Morgan
- //
- //
- // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
- //
- // Permission is hereby granted, free of charge, to any person obtaining
- // a copy of this software and associated documentation files (the
- // "Software"), to deal in the Software without restriction, including
- // without limitation the rights to use, copy, modify, merge, publish,
- // distribute, sublicense, and/or sell copies of the Software, and to
- // permit persons to whom the Software is furnished to do so, subject to
- // the following conditions:
- //
- // The above copyright notice and this permission notice shall be
- // included in all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- //
- using System;
- using System.Collections;
- using System.ComponentModel;
- namespace System.Data {
- [Editor]
- [Serializable]
- internal delegate void DelegateValidateRemoveConstraint(ConstraintCollection sender, Constraint constraintToRemove, ref bool fail,ref string failReason);
-
- /// <summary>
- /// hold collection of constraints for data table
- /// </summary>
- [DefaultEvent ("CollectionChanged")]
- [EditorAttribute("Microsoft.VSDesigner.Data.Design.ConstraintsCollectionEditor, "+Consts.AssemblyMicrosoft_VSDesigner, "System.Drawing.Design.UITypeEditor, "+Consts.AssemblySystem_Drawing )]
- #if !NET_2_0
- [Serializable]
- #endif
- public
- #if NET_2_0
- sealed
- #endif
- class ConstraintCollection : InternalDataCollectionBase
- {
- //private bool beginInit = false;
-
- public event CollectionChangeEventHandler CollectionChanged;
- private DataTable table;
-
- // Keep reference to most recent constraints passed to AddRange()
- // so that they can be added when EndInit() is called.
- private Constraint [] _mostRecentConstraints;
- //Don't allow public instantiation
- //Will be instantianted from DataTable
- internal ConstraintCollection(DataTable table){
- this.table = table;
- }
- internal DataTable Table{
- get{
- return this.table;
- }
- }
- public
- #if !NET_2_0
- virtual
- #endif
- Constraint this[string name] {
- get {
- //If the name is not found we just return null
- int index = IndexOf(name); //case insensitive
- if (-1 == index) return null;
- return this[index];
- }
- }
-
- public
- #if !NET_2_0
- virtual
- #endif
- Constraint this[int index] {
- get {
- if (index < 0 || index >= List.Count)
- throw new IndexOutOfRangeException();
- return (Constraint)List[index];
- }
- }
- private void _handleBeforeConstraintNameChange(object sender, string newName)
- {
- //null or empty
- if (newName == null || newName == "")
- throw new ArgumentException("ConstraintName cannot be set to null or empty " +
- " after it has been added to a ConstraintCollection.");
- if (_isDuplicateConstraintName(newName,(Constraint)sender))
- throw new DuplicateNameException("Constraint name already exists.");
- }
- private bool _isDuplicateConstraintName(string constraintName, Constraint excludeFromComparison)
- {
- foreach (Constraint cst in List) {
- if (String.Compare (constraintName, cst.ConstraintName, false, Table.Locale) == 0 && cst != excludeFromComparison)
- return true;
- }
- return false;
- }
-
- //finds an open name slot of ConstraintXX
- //where XX is a number
- private string _createNewConstraintName()
- {
- bool loopAgain = false;
- int index = 1;
- do
- {
- loopAgain = false;
- foreach (Constraint cst in List)
- {
- //Case insensitive
- if (String.Compare (cst.ConstraintName,
- "Constraint" + index,
- !Table.CaseSensitive,
- Table.Locale)
- == 0)
- {
- loopAgain = true;
- index++;
- break;
- }
- }
- } while (loopAgain);
- return "Constraint" + index.ToString();
-
- }
-
-
- // Overloaded Add method (5 of them)
- // to add Constraint object to the collection
- public void Add(Constraint constraint)
- {
- //not null
- if (null == constraint) throw new ArgumentNullException("Can not add null.");
- if (constraint.InitInProgress)
- throw new ArgumentException ("Hmm .. Failed to Add to collection");
- //check constraint membership
- //can't already exist in this collection or any other
- if (this == constraint.ConstraintCollection)
- throw new ArgumentException("Constraint already belongs to this collection.");
- if (null != constraint.ConstraintCollection)
- throw new ArgumentException("Constraint already belongs to another collection.");
- //check for duplicate name
- if (_isDuplicateConstraintName(constraint.ConstraintName,null) )
- throw new DuplicateNameException("Constraint name already exists.");
- //Allow constraint to run validation rules and setup
- constraint.AddToConstraintCollectionSetup(this); //may throw if it can't setup
- //if name is null or empty give it a name
- if (constraint.ConstraintName == null ||
- constraint.ConstraintName == "" )
- {
- constraint.ConstraintName = _createNewConstraintName();
- }
- //Add event handler for ConstraintName change
- constraint.BeforeConstraintNameChange += new DelegateConstraintNameChange(
- _handleBeforeConstraintNameChange);
- constraint.ConstraintCollection = this;
- List.Add(constraint);
- if (constraint is UniqueConstraint && ((UniqueConstraint)constraint).IsPrimaryKey)
- table.PrimaryKey = ((UniqueConstraint)constraint).Columns;
- OnCollectionChanged( new CollectionChangeEventArgs( CollectionChangeAction.Add, this) );
- }
- public
- #if !NET_2_0
- virtual
- #endif
- Constraint Add(string name, DataColumn column, bool primaryKey)
- {
- UniqueConstraint uc = new UniqueConstraint(name, column, primaryKey);
- Add(uc);
- return uc;
- }
- public
- #if !NET_2_0
- virtual
- #endif
- Constraint Add(string name, DataColumn primaryKeyColumn,
- DataColumn foreignKeyColumn)
- {
- ForeignKeyConstraint fc = new ForeignKeyConstraint(name, primaryKeyColumn,
- foreignKeyColumn);
- Add(fc);
- return fc;
- }
- public
- #if !NET_2_0
- virtual
- #endif
- Constraint Add(string name, DataColumn[] columns, bool primaryKey)
- {
- UniqueConstraint uc = new UniqueConstraint(name, columns, primaryKey);
- Add(uc);
- return uc;
- }
- public
- #if !NET_2_0
- virtual
- #endif
- Constraint Add(string name, DataColumn[] primaryKeyColumns,
- DataColumn[] foreignKeyColumns)
- {
- ForeignKeyConstraint fc = new ForeignKeyConstraint(name, primaryKeyColumns,
- foreignKeyColumns);
- Add(fc);
- return fc;
- }
- public void AddRange(Constraint[] constraints)
- {
- //When AddRange() occurs after BeginInit,
- //it does not add any elements to the collection until EndInit is called.
- if (Table.InitInProgress) {
- // Keep reference so that they can be added when EndInit() is called.
- _mostRecentConstraints = constraints;
- return;
- }
-
- if (constraints == null)
- return;
- for (int i=0; i < constraints.Length; ++i) {
- if (constraints [i] == null)
- continue;
- Add (constraints [i]);
- }
- }
- // Helper AddRange() - Call this function when EndInit is called
- // keeps track of the Constraints most recently added and adds them
- // to the collection
- internal void PostAddRange ()
- {
- if (_mostRecentConstraints == null)
- return;
- // Check whether the constraint is Initialized
- // If not, initialize before adding to collection
- for (int i = 0; i < _mostRecentConstraints.Length; i++) {
- Constraint c = _mostRecentConstraints [i];
- if (c == null)
- continue;
- if (c.InitInProgress)
- c.FinishInit (Table);
- Add (c);
- }
- _mostRecentConstraints = null;
- }
- public bool CanRemove(Constraint constraint)
- {
- return constraint.CanRemoveFromCollection(this, false);
- }
- public void Clear()
- {
- // Clear should also remove PrimaryKey
- Table.PrimaryKey = null;
-
- //CanRemove? See Lamespec below.
- //the Constraints have a reference to us
- //and we listen to name change events
- //we should remove these before clearing
- foreach (Constraint con in List)
- {
- con.ConstraintCollection = null;
- con.BeforeConstraintNameChange -= new DelegateConstraintNameChange(
- _handleBeforeConstraintNameChange);
- }
- //LAMESPEC: MSFT implementation allows this
- //even when a ForeignKeyConstraint exist for a UniqueConstraint
- //thus violating the CanRemove logic
- //CanRemove will throws Exception incase of the above
- List.Clear(); //Will violate CanRemove rule
- OnCollectionChanged( new CollectionChangeEventArgs(CollectionChangeAction.Refresh, this) );
- }
- public bool Contains(string name)
- {
- return (-1 != IndexOf(name));
- }
- public int IndexOf(Constraint constraint)
- {
- return List.IndexOf(constraint);
- }
- public
- #if !NET_2_0
- virtual
- #endif
- int IndexOf(string constraintName)
- {
- //LAMESPEC: Spec doesn't say case insensitive
- //it should to be consistant with the other
- //case insensitive comparisons in this class
- int index = 0;
- foreach (Constraint con in List)
- {
- if (String.Compare (constraintName, con.ConstraintName, !Table.CaseSensitive, Table.Locale) == 0)
- {
- return index;
- }
- index++;
- }
- return -1; //not found
- }
- public void Remove(Constraint constraint) {
- //LAMESPEC: spec doesn't document the ArgumentException the
- //will be thrown if the CanRemove rule is violated
-
- //LAMESPEC: spec says an exception will be thrown
- //if the element is not in the collection. The implementation
- //doesn't throw an exception. ArrayList.Remove doesn't throw if the
- //element doesn't exist
- //ALSO the overloaded remove in the spec doesn't say it throws any exceptions
- //not null
- if (null == constraint) throw new ArgumentNullException();
- if (!constraint.CanRemoveFromCollection(this, true))
- return;
-
- constraint.RemoveFromConstraintCollectionCleanup(this);
- List.Remove(constraint);
- OnCollectionChanged( new CollectionChangeEventArgs(CollectionChangeAction.Remove,this));
- }
- public void Remove(string name)
- {
- //if doesn't exist fail quietly
- int index = IndexOf(name);
- if (-1 == index) return;
- Remove(this[index]);
- }
- public void RemoveAt(int index)
- {
- Remove(this[index]);
- }
- protected override ArrayList List {
- get{
- return base.List;
- }
- }
- protected
- #if !NET_2_0
- virtual
- #endif
- void OnCollectionChanged( CollectionChangeEventArgs ccevent)
- {
- if (null != CollectionChanged)
- {
- CollectionChanged(this, ccevent);
- }
- }
- }
- }
|