// // System.Data.DataRelationCollection.cs // // Author: // Christopher Podurgiel (cpodurgiel@msn.com) // Daniel Morgan // Tim Coleman (tim@timcoleman.com) // Alan Tam Siu Lung // // (C) Chris Podurgiel // (C) 2002 Daniel Morgan // Copyright (C) Tim Coleman, 2002 // using System; using System.Collections; using System.ComponentModel; namespace System.Data { /// /// Represents the collection of DataRelation objects for this DataSet. /// [Editor] [DefaultEvent ("CollectionChanged")] [Serializable] public abstract class DataRelationCollection : InternalDataCollectionBase { /// /// Summary description for DataTableRelationCollection. /// internal class DataSetRelationCollection : DataRelationCollection { private DataSet dataSet; /// /// Initializes a new instance of the DataSetRelationCollection class. /// internal DataSetRelationCollection (DataSet dataSet) { this.dataSet = dataSet; } /// /// Gets the DataRelation object specified by name. /// public override DataRelation this [string name] { get { int index = IndexOf (name, true); return index < 0 ? null : (DataRelation) list[index]; } } /// /// Gets the DataRelation object at the specified index. /// public override DataRelation this [int index] { get { return List [index] as DataRelation; } } protected override DataSet GetDataSet() { return dataSet; } /// /// Performs verification on the table. /// /// The relation to check. protected override void AddCore (DataRelation relation) { base.AddCore (relation); if (relation.ChildTable.DataSet != this.dataSet || relation.ParentTable.DataSet != this.dataSet) throw new DataException (); relation.SetDataSet (dataSet); relation.ParentTable.ChildRelations.Add (relation); relation.ChildTable.ParentRelations.Add (relation); ForeignKeyConstraint foreignKeyConstraint = null; if (relation.createConstraints) { UniqueConstraint uniqueConstraint = null; ConstraintCollection parentConstrains = relation.ParentTable.Constraints; // find if the unique constraint already exists in the parent table. foreach (Constraint o in parentConstrains) { if (o is UniqueConstraint) { UniqueConstraint uc = (UniqueConstraint) o; if (uc.Columns.Length == relation.ParentColumns.Length) { bool allColumnsEqual = true; for (int columnCnt = 0; columnCnt < uc.Columns.Length; ++columnCnt) { if (uc.Columns[columnCnt] != relation.ParentColumns[columnCnt]) { allColumnsEqual = false; break; } } if (allColumnsEqual) { uniqueConstraint = uc; break; } } } } // if we did not find the unique constraint in the parent table. // we generate new uniqueconastraint and add it to the parent table. if (uniqueConstraint == null) { uniqueConstraint = new UniqueConstraint(relation.ParentColumns, false); relation.ParentTable.Constraints.Add(uniqueConstraint); } foreignKeyConstraint = new ForeignKeyConstraint (relation.RelationName, relation.ParentColumns, relation.ChildColumns); relation.ChildTable.Constraints.Add (foreignKeyConstraint); relation.SetParentKeyConstraint (uniqueConstraint); relation.SetChildKeyConstraint (foreignKeyConstraint); } } public override void AddRange (DataRelation[] relations) { base.AddRange (relations); } public override void Clear () { for (int i = 0; i < Count; i++) RemoveCore(this[i]); base.Clear(); } protected override void RemoveCore (DataRelation relation) { relation.SetDataSet (null); relation.ParentTable.ChildRelations.Remove (relation); relation.ChildTable.ParentRelations.Remove (relation); relation.SetParentKeyConstraint (null); relation.SetChildKeyConstraint (null); } protected override ArrayList List { get { return base.List; } } } /// /// Summary description for DataTableRelationCollection. /// internal class DataTableRelationCollection : DataRelationCollection { private DataTable dataTable; /// /// Initializes a new instance of the DataTableRelationCollection class. /// internal DataTableRelationCollection (DataTable dataTable) { this.dataTable = dataTable; } /// /// Gets the DataRelation object specified by name. /// public override DataRelation this [string name] { get { int index = IndexOf (name, true); return index < 0 ? null : (DataRelation) list[index]; } } /// /// Gets the DataRelation object at the specified index. /// public override DataRelation this [int index] { get { return List [index] as DataRelation; } } protected override DataSet GetDataSet() { return dataTable.DataSet; } protected override void AddCore (DataRelation relation) { base.AddCore (relation); } protected override void RemoveCore (DataRelation relation) { base.RemoveCore (relation); } protected override ArrayList List { get { return base.List; } } } private int defaultNameIndex; private bool inTransition; int index; /// /// Initializes a new instance of the DataRelationCollection class. /// protected DataRelationCollection () : base () { defaultNameIndex = 1; inTransition = false; } /// /// Gets the DataRelation object specified by name. /// public abstract DataRelation this[string name]{get;} /// /// Gets the DataRelation object at the specified index. /// public abstract DataRelation this[int index]{get;} #region Add Methods private string GetNextDefaultRelationName () { int index = 1; string defRelationName = "Relation" +index; for (; Contains (defRelationName); ++index) { defRelationName = "Relation" + index; } return defRelationName; } /// /// Adds a DataRelation to the DataRelationCollection. /// /// The DataRelation to add to the collection. [MonoTODO] public void Add(DataRelation relation) { this.AddCore (relation); if(relation.RelationName == string.Empty) relation.RelationName = GenerateRelationName(); CollectionChangeEventArgs e = new CollectionChangeEventArgs(CollectionChangeAction.Add, this); //List.Add(relation); OnCollectionChanged(e); } private string GenerateRelationName() { index++; return "Relation" + index; } /// /// Creates a relation given the parameters and adds it to the collection. The name is defaulted. /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection. /// An InvalidConstraintException is generated if the relation can't be created based on the parameters. /// The CollectionChanged event is fired if it succeeds. /// /// parent column of relation. /// child column of relation. /// The created DataRelation. public virtual DataRelation Add(DataColumn parentColumn, DataColumn childColumn) { DataRelation dataRelation = new DataRelation(GetNextDefaultRelationName (), parentColumn, childColumn); Add(dataRelation); return dataRelation; } /// /// Creates a relation given the parameters and adds it to the collection. The name is defaulted. /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection. /// An InvalidConstraintException is generated if the relation can't be created based on the parameters. /// The CollectionChanged event is raised if it succeeds. /// /// An array of parent DataColumn objects. /// An array of child DataColumn objects. /// The created DataRelation. public virtual DataRelation Add(DataColumn[] parentColumns, DataColumn[] childColumns) { DataRelation dataRelation = new DataRelation(GetNextDefaultRelationName (), parentColumns, childColumns); Add(dataRelation); return dataRelation; } /// /// Creates a relation given the parameters and adds it to the collection. /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection. /// A DuplicateNameException is generated if this collection already has a relation with the same name (case insensitive). /// An InvalidConstraintException is generated if the relation can't be created based on the parameters. /// The CollectionChanged event is raised if it succeeds. /// /// The name of the relation. /// parent column of relation. /// The created DataRelation. /// public virtual DataRelation Add(string name, DataColumn parentColumn, DataColumn childColumn) { //If no name was supplied, give it a default name. if (name == null || name == "") name = GetNextDefaultRelationName (); DataRelation dataRelation = new DataRelation(name, parentColumn, childColumn); Add(dataRelation); return dataRelation; } /// /// Creates a DataRelation with the specified name, and arrays of parent and child columns, and adds it to the collection. /// /// The name of the DataRelation to create. /// An array of parent DataColumn objects. /// An array of child DataColumn objects. /// The created DataRelation. public virtual DataRelation Add(string name, DataColumn[] parentColumns, DataColumn[] childColumns) { //If no name was supplied, give it a default name. if (name == null || name == "") name = GetNextDefaultRelationName (); DataRelation dataRelation = new DataRelation(name, parentColumns, childColumns); Add(dataRelation); return dataRelation; } /// /// Creates a relation given the parameters and adds it to the collection. /// An ArgumentException is generated if this relation already belongs to this collection or belongs to another collection. /// A DuplicateNameException is generated if this collection already has a relation with the same name (case insensitive). /// An InvalidConstraintException is generated if the relation can't be created based on the parameters. /// The CollectionChanged event is raised if it succeeds. /// /// The name of the relation. /// parent column of relation. /// child column of relation. /// true to create constraints; otherwise false. (default is true) /// The created DataRelation. public virtual DataRelation Add(string name, DataColumn parentColumn, DataColumn childColumn, bool createConstraints) { //If no name was supplied, give it a default name. if (name == null || name == "") name = GetNextDefaultRelationName (); DataRelation dataRelation = new DataRelation(name, parentColumn, childColumn, createConstraints); Add(dataRelation); return dataRelation; } /// /// Creates a DataRelation with the specified name, arrays of parent and child columns, /// and value specifying whether to create a constraint, and adds it to the collection. /// /// The name of the DataRelation to create. /// An array of parent DataColumn objects. /// An array of child DataColumn objects. /// true to create a constraint; otherwise false. /// The created DataRelation. public virtual DataRelation Add(string name, DataColumn[] parentColumns, DataColumn[] childColumns, bool createConstraints) { //If no name was supplied, give it a default name. if (name == null || name == "") name = GetNextDefaultRelationName (); DataRelation dataRelation = new DataRelation(name, parentColumns, childColumns, createConstraints); Add(dataRelation); return dataRelation; } #endregion /// /// Performs verification on the table. /// /// The relation to check. [MonoTODO] protected virtual void AddCore(DataRelation relation) { if (relation == null) { //TODO: Issue a good exception message. throw new ArgumentNullException(); } if(List.IndexOf(relation) != -1) { //TODO: Issue a good exception message. throw new ArgumentException(); } // check if the collection has a relation with the same name. int tmp = IndexOf(relation.RelationName); // if we found a relation with same name we have to check // that it is the same case. // indexof can return a table with different case letters. if (tmp != -1) { if(relation.RelationName == this[tmp].RelationName) throw new DuplicateNameException("A DataRelation named '" + relation.RelationName + "' already belongs to this DataSet."); } List.Add(relation); } /// /// Copies the elements of the specified DataRelation array to the end of the collection. /// /// The array of DataRelation objects to add to the collection. public virtual void AddRange(DataRelation[] relations) { foreach (DataRelation relation in relations) Add(relation); } public virtual bool CanRemove(DataRelation relation) { if (relation == null || !GetDataSet().Equals(relation.DataSet)) return false; return true; } public virtual void Clear() { List.Clear(); } public virtual bool Contains(string name) { return (-1 != IndexOf (name, false)); } private CollectionChangeEventArgs CreateCollectionChangeEvent (CollectionChangeAction action) { return new CollectionChangeEventArgs (action, this); } protected abstract DataSet GetDataSet(); public virtual int IndexOf(DataRelation relation) { return List.IndexOf(relation); } public virtual int IndexOf(string relationName) { return IndexOf(relationName, false); } private int IndexOf (string name, bool error) { int count = 0, match = -1; for (int i = 0; i < list.Count; i++) { String name2 = ((DataRelation) list[i]).RelationName; if (String.Compare (name, name2, true) == 0) { if (String.Compare (name, name2, false) == 0) return i; match = i; count++; } } if (count == 1) return match; if (count > 1 && error) throw new ArgumentException ("There is no match for the name in the same case and there are multiple matches in different case."); return -1; } protected virtual void OnCollectionChanged (CollectionChangeEventArgs ccevent) { if (CollectionChanged != null) CollectionChanged (this, ccevent); } [MonoTODO] protected internal virtual void OnCollectionChanging (CollectionChangeEventArgs ccevent) { throw new NotImplementedException (); } public void Remove (DataRelation relation) { RemoveCore (relation); List.Remove (relation); string name = "Relation" + index; if (relation.RelationName == name) index--; OnCollectionChanged (CreateCollectionChangeEvent (CollectionChangeAction.Remove)); } public void Remove (string name) { Remove ((DataRelation) List[IndexOf (name)]); } public void RemoveAt (int index) { Remove(this[index]); } [MonoTODO] protected virtual void RemoveCore(DataRelation relation) { // TODO: What have to be done? } [ResDescriptionAttribute ("Occurs whenever this collection's membership changes.")] public event CollectionChangeEventHandler CollectionChanged; } }