BindingFlags.Public needed here as Exception.HResult is now public in .NET 4.5. This...
[mono.git] / mcs / class / System.Data / System.Data / ForeignKeyConstraint.cs
index a698350d66b456d71579f538e31d02c0af744f14..965810599ccbff1dc9aad2ad54ea69780fa51574 100644 (file)
@@ -42,7 +42,9 @@ namespace System.Data {
        [Editor ("Microsoft.VSDesigner.Data.Design.ForeignKeyConstraintEditor, " + Consts.AssemblyMicrosoft_VSDesigner,
                 "System.Drawing.Design.UITypeEditor, " + Consts.AssemblySystem_Drawing)]
        [DefaultProperty ("ConstraintName")]
+#if !NET_2_0
        [Serializable]
+#endif
        public class ForeignKeyConstraint : Constraint 
        {
                private UniqueConstraint _parentUniqueConstraint;
@@ -53,12 +55,15 @@ namespace System.Data {
                private Rule _deleteRule = Rule.Cascade;
                private Rule _updateRule = Rule.Cascade;
                private AcceptRejectRule _acceptRejectRule = AcceptRejectRule.None;
-           private string _parentTableName;
-        private string _childTableName;
+               private string _parentTableName;
+#if NET_2_0
+               private string _parentTableNamespace;
+#endif
+               private string _childTableName;
+
                //FIXME: remove those; and use only DataColumns[]
-        private string [] _parentColumnNames;
-        private string [] _childColumnNames;
-        private bool _dataColsNotValidated = false;
+               private string [] _parentColumnNames;
+               private string [] _childColumnNames;
                        
                #region Constructors
 
@@ -92,109 +97,138 @@ namespace System.Data {
                {
                        _foreignKeyConstraint(constraintName, parentColumns, childColumns);
                }
-               
+
                //special case
                [Browsable (false)]
                public ForeignKeyConstraint(string constraintName, string parentTableName, string[] parentColumnNames, string[] childColumnNames, AcceptRejectRule acceptRejectRule, Rule deleteRule, Rule updateRule) 
                {
-                       _dataColsNotValidated = true;
-            base.ConstraintName = constraintName;
-                                                                                        
-            // "parentTableName" is searched in the "DataSet" to which the "DataTable"
-            // from which AddRange() is called
-            // childTable is the "DataTable" which calls AddRange()
-                                                                                        
-            // Keep reference to parentTableName to resolve later
-            _parentTableName = parentTableName;
-                                                                                        
-            // Keep reference to parentColumnNames to resolve later
-            _parentColumnNames = parentColumnNames;
-                                                                                        
-            // Keep reference to childColumnNames to resolve later
-            _childColumnNames = childColumnNames;
-                                                                                        
-            _acceptRejectRule = acceptRejectRule;
-            _deleteRule = deleteRule;
-            _updateRule = updateRule;
+                       int i;
+                       InitInProgress = true;
+                       base.ConstraintName = constraintName;
+
+                       // "parentTableName" is searched in the "DataSet" to which the "DataTable"
+                       // from which AddRange() is called
+                       // childTable is the "DataTable" which calls AddRange()
 
+                       // Keep reference to parentTableName to resolve later
+                       _parentTableName = parentTableName;
+
+                       // Keep a copy of parentColumnNames to resolve later
+                       _parentColumnNames = new string [parentColumnNames.Length];
+                       for (i = 0; i < parentColumnNames.Length; i++)
+                              _parentColumnNames[i] = parentColumnNames[i];
+                       
+                       // Keep a copy of childColumnNames to resolve later
+                       _childColumnNames = new string [childColumnNames.Length];
+                       for (i = 0; i < childColumnNames.Length; i++)
+                              _childColumnNames[i] = childColumnNames[i];
+                       
+
+                       _acceptRejectRule = acceptRejectRule;
+                       _deleteRule = deleteRule;
+                       _updateRule = updateRule;
                }
 
-               internal void postAddRange (DataTable childTable)
-        {
-            // LAMESPEC - Does not say that this is mandatory
-            // Check whether childTable belongs to a DataSet
-            if (childTable.DataSet == null)
-                    throw new InvalidConstraintException ("ChildTable : " + childTable.TableName + " does not belong to any DataSet");
-            DataSet dataSet = childTable.DataSet;
-            _childTableName = childTable.TableName;
-            // Search for the parentTable in the childTable's DataSet
-            if (!dataSet.Tables.Contains (_parentTableName))
-                    throw new InvalidConstraintException ("Table : " + _parentTableName + "does not exist in DataSet : " + dataSet);
-                                                                                        
-            // Keep reference to parentTable
-            DataTable parentTable = dataSet.Tables [_parentTableName];
-                                                                                        
-            int i = 0, j = 0;
-                                                                                        
-            // LAMESPEC - Does not say which Exception is thrown
-            if (_parentColumnNames.Length < 0 || _childColumnNames.Length < 0)
-                    throw new InvalidConstraintException ("Neither parent nor child columns can be zero length");
-            // LAMESPEC - Does not say which Exception is thrown
-            if (_parentColumnNames.Length != _childColumnNames.Length)
-                               throw new InvalidConstraintException ("Both parent and child columns must be of same length");                                                                                                    
-            DataColumn []parentColumns = new DataColumn [_parentColumnNames.Length];
-            DataColumn []childColumns = new DataColumn [_childColumnNames.Length];
-                                                                                        
-            // Search for the parentColumns in parentTable
-            foreach (string parentCol in _parentColumnNames){
-                    if (!parentTable.Columns.Contains (parentCol))
-                            throw new InvalidConstraintException ("Table : " + _parentTableName + "does not contain the column :" + parentCol);
-                    parentColumns [i++] = parentTable. Columns [parentCol];
-            }
-            // Search for the childColumns in childTable
-            foreach (string childCol in _childColumnNames){
-                    if (!childTable.Columns.Contains (childCol))
-                            throw new InvalidConstraintException ("Table : " + _childTableName + "does not contain the column : " + childCol);
-                    childColumns [j++] = childTable.Columns [childCol];
-            }
-            _validateColumns (parentColumns, childColumns);
-            _parentColumns = parentColumns;
-            _childColumns = childColumns;
+               internal override void FinishInit (DataTable childTable)
+               {
+                       if (childTable.DataSet == null)
+                               throw new InvalidConstraintException ("ChildTable : " + childTable.TableName + " does not belong to any DataSet");
+
+                       DataSet dataSet = childTable.DataSet;
+                       _childTableName = childTable.TableName;
+
+                       if (!dataSet.Tables.Contains (_parentTableName))
+                               throw new InvalidConstraintException ("Table : " + _parentTableName + "does not exist in DataSet : " + dataSet);
+
+                       DataTable parentTable = dataSet.Tables [_parentTableName];
+
+                       int i = 0, j = 0;
+
+                       if (_parentColumnNames.Length < 0 || _childColumnNames.Length < 0)
+                               throw new InvalidConstraintException ("Neither parent nor child columns can be zero length");
+
+                       if (_parentColumnNames.Length != _childColumnNames.Length)
+                               throw new InvalidConstraintException ("Both parent and child columns must be of same length");                                                                                                    
+                       DataColumn[] parentColumns = new DataColumn [_parentColumnNames.Length];
+                       DataColumn[] childColumns = new DataColumn [_childColumnNames.Length];
+
+                       foreach (string parentCol in _parentColumnNames){
+                               if (!parentTable.Columns.Contains (parentCol))
+                                       throw new InvalidConstraintException ("Table : " + _parentTableName + "does not contain the column :" + parentCol);
+                               parentColumns [i++] = parentTable. Columns [parentCol];
+                       }
+
+                       foreach (string childCol in _childColumnNames){
+                               if (!childTable.Columns.Contains (childCol))
+                                       throw new InvalidConstraintException ("Table : " + _childTableName + "does not contain the column : " + childCol);
+                               childColumns [j++] = childTable.Columns [childCol];
+                       }
+                       _validateColumns (parentColumns, childColumns);
+                       _parentColumns = parentColumns;
+                       _childColumns = childColumns;
+#if NET_2_0
+                       parentTable.Namespace = _parentTableNamespace;
+#endif
+                       InitInProgress = false;
                }
-                       
+
 #if NET_2_0
-               [MonoTODO]
+               [Browsable (false)]
                public ForeignKeyConstraint (string constraintName, string parentTableName, string parentTableNamespace, string[] parentColumnNames, string[] childColumnNames, AcceptRejectRule acceptRejectRule, Rule deleteRule, Rule updateRule)
                {
-                       throw new NotImplementedException ();
+                       InitInProgress = true;
+                       base.ConstraintName = constraintName;
+
+                       // "parentTableName" is searched in the "DataSet" to which the "DataTable"
+                       // from which AddRange() is called
+                       // childTable is the "DataTable" which calls AddRange()
+
+                       // Keep reference to parentTableName to resolve later
+                       _parentTableName = parentTableName;
+                       _parentTableNamespace = parentTableNamespace;
+
+                       // Keep reference to parentColumnNames to resolve later
+                       _parentColumnNames = parentColumnNames;
+
+                       // Keep reference to childColumnNames to resolve later
+                       _childColumnNames = childColumnNames;
+
+                       _acceptRejectRule = acceptRejectRule;
+                       _deleteRule = deleteRule;
+                       _updateRule = updateRule;
                }
 #endif
 
                private void _foreignKeyConstraint(string constraintName, DataColumn[] parentColumns,
                                DataColumn[] childColumns)
                {
-
+                       int i;
                        //Validate 
                        _validateColumns(parentColumns, childColumns);
 
                        //Set Constraint Name
                        base.ConstraintName = constraintName;   
 
-                       //Keep reference to columns
-                       _parentColumns = parentColumns;
-                       _childColumns = childColumns;
+                       //copy the columns - Do not keep reference #672113
+                       _parentColumns = new DataColumn [parentColumns.Length];
+                       for (i = 0; i < parentColumns.Length; i++)
+                              _parentColumns[i] = parentColumns[i];
+                       
+                       _childColumns = new DataColumn [childColumns.Length];                   
+                       for (i = 0; i < childColumns.Length; i++)
+                              _childColumns[i] = childColumns[i];
                }
 
-               #endregion // Constructors
+#endregion // Constructors
 
-               #region Helpers
+#region Helpers
 
                private void _validateColumns(DataColumn[] parentColumns, DataColumn[] childColumns)
                {
                        //not null
                        if (null == parentColumns || null == childColumns) 
                                throw new ArgumentNullException();
-                       
+
                        //at least one element in each array
                        if (parentColumns.Length < 1 || childColumns.Length < 1)
                                throw new ArgumentException("Neither ParentColumns or ChildColumns can't be" +
@@ -249,43 +283,29 @@ namespace System.Data {
                        }       
 
 
+                       int identicalCols = 0;
                        for (int i = 0; i < parentColumns.Length; i++)
                        {
                                DataColumn pc = parentColumns[i];
                                DataColumn cc = childColumns[i];
                                
-                               //Can't be the same column
-                               if (pc == cc)
-                                       throw new InvalidOperationException("Parent and child columns can't be the same column.");
+                               if (pc == cc) {
+                                       identicalCols++;
+                                       continue;
+                               }
 
-                               if (! pc.DataType.Equals(cc.DataType))
-                               {
+                               if (!pc.DataTypeMatches (cc)) {
                                        //LAMESPEC: spec says throw InvalidConstraintException
                                        //              implementation throws InvalidOperationException
-                                       throw new InvalidConstraintException("Parent column is not type compatible with it's child"
+                                       throw new InvalidOperationException ("Parent column is not type compatible with it's child"
                                                + " column.");
                                }
-                                       
                        }
+                       if (identicalCols == parentColumns.Length)
+                               throw new InvalidOperationException ("Property not accessible because 'ParentKey and ChildKey are identical.'.");
                        
                }
                
-
-
-               private void _validateRemoveParentConstraint(ConstraintCollection sender, 
-                               Constraint constraint, ref bool cancel, ref string failReason)
-               {
-#if !NET_1_1
-                       //if we hold a reference to the parent then cancel it
-                       if (constraint == _parentUniqueConstraint) 
-                       {
-                               cancel = true;
-                               failReason = "Cannot remove UniqueConstraint because the"
-                                       + " ForeignKeyConstraint " + this.ConstraintName + " exists.";
-                       }
-#endif
-               }
-               
                //Checks to see if a related unique constraint exists
                //if it doesn't then a unique constraint is created.
                //if a unique constraint can't be created an exception will be thrown
@@ -310,11 +330,7 @@ namespace System.Data {
 
                        //keep reference
                        _parentUniqueConstraint = uc;
-                       //parentColumns [0].Table.Constraints.Add (uc);
-                       //if this unique constraint is attempted to be removed before us
-                       //we can fail the validation
-                       //collection.ValidateRemoveConstraint += new DelegateValidateRemoveConstraint(
-                       //              _validateRemoveParentConstraint);
+                       _parentUniqueConstraint.ChildConstraint = this;
                }
                
                
@@ -323,7 +339,9 @@ namespace System.Data {
                #region Properties
 
                [DataCategory ("Data")]
+#if !NET_2_0
                [DataSysDescription ("For accept and reject changes, indicates what kind of cascading should take place across this relation.")]
+#endif
                [DefaultValue (AcceptRejectRule.None)]
                public virtual AcceptRejectRule AcceptRejectRule {
                        get { return _acceptRejectRule; }
@@ -331,14 +349,18 @@ namespace System.Data {
                }
 
                [DataCategory ("Data")]
+#if !NET_2_0
                [DataSysDescription ("Indicates the child columns of this constraint.")]
+#endif
                [ReadOnly (true)]
                public virtual DataColumn[] Columns {
                        get { return _childColumns; }
                }
 
                [DataCategory ("Data")]
+#if !NET_2_0
                [DataSysDescription ("For deletions, indicates what kind of cascading should take place across this relation.")]
+#endif
                [DefaultValue (Rule.Cascade)]
                public virtual Rule DeleteRule {
                        get { return _deleteRule; }
@@ -346,7 +368,9 @@ namespace System.Data {
                }
 
                [DataCategory ("Data")]
+#if !NET_2_0
                [DataSysDescription ("For updates, indicates what kind of cascading should take place across this relation.")]
+#endif
                [DefaultValue (Rule.Cascade)]
                public virtual Rule UpdateRule {
                        get { return _updateRule; }
@@ -354,14 +378,18 @@ namespace System.Data {
                }
 
                [DataCategory ("Data")] 
+#if !NET_2_0
                [DataSysDescription ("Indicates the parent columns of this constraint.")]
+#endif
                [ReadOnly (true)]
                public virtual DataColumn[] RelatedColumns {
                        get { return _parentColumns; }
                }
 
                [DataCategory ("Data")] 
+#if !NET_2_0
                [DataSysDescription ("Indicates the child table of this constraint.")]
+#endif
                [ReadOnly (true)]
                public virtual DataTable RelatedTable {
                        get {
@@ -374,7 +402,9 @@ namespace System.Data {
                }
 
                [DataCategory ("Data")]
+#if !NET_2_0
                [DataSysDescription ("Indicates the table of this constraint.")]
+#endif
                [ReadOnly (true)]
                public override DataTable Table {
                        get {
@@ -386,13 +416,9 @@ namespace System.Data {
                        }
                }
 
-               internal bool DataColsNotValidated
-               {
-            get { 
-                               return (_dataColsNotValidated); 
-                       }
-        }
-
+               internal UniqueConstraint ParentConstraint {
+                       get { return _parentUniqueConstraint; }
+               }
 
                #endregion // Properties
 
@@ -459,8 +485,6 @@ namespace System.Data {
                        //we must have a unique constraint on the parent
                        _ensureUniqueConstraintExists(collection, _parentColumns);
                        
-                       //Make sure we can create this thing
-                       //AssertConstraint(); 
                        if ( (Table.DataSet != null && Table.DataSet.EnforceConstraints)
                             || (Table.DataSet == null && Table.EnforceConstraints)) {
                                if (IsConstraintViolated())
@@ -474,10 +498,11 @@ namespace System.Data {
                internal override void RemoveFromConstraintCollectionCleanup( 
                                ConstraintCollection collection)
                {
+                       _parentUniqueConstraint.ChildConstraint = null;
                        Index = null;
                }
                
-               protected internal override bool IsConstraintViolated()
+               internal override bool IsConstraintViolated()
                {
                        if (Table.DataSet == null || RelatedTable.DataSet == null) 
                                return false;