2 // System.Data.Constraint.cs
5 // Franklin Wise <gracenote@earthlink.net>
7 // Tim Coleman (tim@timcoleman.com)
10 // (C) Ximian, Inc. 2002
11 // Copyright (C) Tim Coleman, 2002
15 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
17 // Permission is hereby granted, free of charge, to any person obtaining
18 // a copy of this software and associated documentation files (the
19 // "Software"), to deal in the Software without restriction, including
20 // without limitation the rights to use, copy, modify, merge, publish,
21 // distribute, sublicense, and/or sell copies of the Software, and to
22 // permit persons to whom the Software is furnished to do so, subject to
23 // the following conditions:
25 // The above copyright notice and this permission notice shall be
26 // included in all copies or substantial portions of the Software.
28 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38 using System
.Collections
;
39 using System
.ComponentModel
;
40 using System
.Runtime
.InteropServices
;
41 using System
.Runtime
.Serialization
;
43 namespace System
.Data
{
45 internal delegate void DelegateConstraintNameChange (object sender
, string newName
);
47 [DefaultProperty ("ConstraintName")]
49 [TypeConverterAttribute (typeof (ConstraintConverter
))]
50 public abstract class Constraint
52 internal event DelegateConstraintNameChange BeforeConstraintNameChange
;
54 //if constraintName is not set then a name is
55 //created when it is added to
56 //the ConstraintCollection
57 //it can not be set to null, empty or duplicate
58 //once it has been added to the collection
59 private string _constraintName
;
60 private PropertyCollection _properties
;
64 //Used for membership checking
65 private ConstraintCollection _constraintCollection
;
69 protected Constraint ()
72 _properties
= new PropertyCollection();
75 [CLSCompliant (false)]
76 protected internal virtual DataSet _DataSet
{
77 get { return dataSet; }
80 [DataCategory ("Data")]
81 [DataSysDescription ("Indicates the name of this constraint.")]
83 public virtual string ConstraintName
{
84 get{ return _constraintName == null ? "" : _constraintName; }
86 //This should only throw an exception when it
87 //is a member of a ConstraintCollection which
88 //means we should let the ConstraintCollection
89 //handle exceptions when this value changes
90 _onConstraintNameChange(value);
91 _constraintName
= value;
96 [DataCategory ("Data")]
97 [DataSysDescription ("The collection that holds custom user information.")]
98 public PropertyCollection ExtendedProperties
{
99 get { return _properties; }
102 [DataSysDescription ("Indicates the table of this constraint.")]
103 public abstract DataTable Table
{
107 internal ConstraintCollection ConstraintCollection
{
108 get{ return _constraintCollection; }
109 set{ _constraintCollection = value; }
112 private void _onConstraintNameChange (string newName
)
114 if (null != BeforeConstraintNameChange
)
116 BeforeConstraintNameChange (this, newName
);
120 //call once before adding a constraint to a collection
121 //will throw an exception to prevent the add if a rule is broken
122 internal virtual void AddToConstraintCollectionSetup (ConstraintCollection collection
)
126 internal virtual void AssertConstraint ()
130 internal virtual void AssertConstraint (DataRow row
)
134 internal virtual void RollbackAssert (DataRow row
)
138 //call once before removing a constraint to a collection
139 //can throw an exception to prevent the removal
140 internal virtual void RemoveFromConstraintCollectionCleanup (ConstraintCollection collection
)
145 protected void CheckStateForProperty ()
147 throw new NotImplementedException ();
150 protected internal void SetDataSet (DataSet dataSet
)
152 this.dataSet
= dataSet
;
165 internal void UpdateIndex (DataRow row
)
167 if (row
.RowState
== DataRowState
.Detached
|| row
.RowState
== DataRowState
.Unchanged
)
168 Index
.Insert (new Node (row
), DataRowVersion
.Default
);
169 else if ((row
.RowState
== DataRowState
.Modified
) || (row
.RowState
== DataRowState
.Added
)) {
170 // first we check if the values of the key changed.
171 bool keyChanged
= false;
172 for (int i
= 0; i
< Index
.Columns
.Length
; i
++) {
173 if (row
[Index
.Columns
[i
], DataRowVersion
.Default
] != row
[Index
.Columns
[i
], DataRowVersion
.Current
]) {
177 // if key changed we first try to insert a new node
178 // and,if succeded, we delete the row's old node.
181 // insert new node for the row
182 // note : may throw if not succeded
183 Index
.Insert (new Node (row
), DataRowVersion
.Default
);
185 // delete the row's node
191 internal void RollbackIndex (DataRow row
)
193 Node n
= Index
.Find(row
, DataRowVersion
.Default
);
195 throw new ConstraintException("Row was not found in constraint index");
197 // first remove the node inserted as a result of last AssertConstraint on the row
200 // if the row is not detached we should add back to the index
201 // node corresponding to row value before AssertConstraint was called
202 if(row
.RowState
!= DataRowState
.Detached
){
203 // since index before we updated index was ok, insert should always suceed
204 // maybe we still need to try/catch here
205 Index
.Insert(new Node(row
), DataRowVersion
.Current
);
211 /// Gets the ConstraintName, if there is one, as a string.
213 public override string ToString ()
215 return _constraintName
== null ? "" : _constraintName
;