This commit was manufactured by cvs2svn to create branch 'mono-1-0'.
[mono.git] / mcs / class / System.Data / System.Data / Constraint.cs
1 //
2 // System.Data.Constraint.cs
3 //
4 // Author:
5 //      Franklin Wise <gracenote@earthlink.net>
6 //      Daniel Morgan
7 //      Tim Coleman (tim@timcoleman.com)
8 //   
9 //
10 // (C) Ximian, Inc. 2002
11 // Copyright (C) Tim Coleman, 2002
12 //
13
14 //
15 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
16 //
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:
24 // 
25 // The above copyright notice and this permission notice shall be
26 // included in all copies or substantial portions of the Software.
27 // 
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.
35 //
36
37 using System;
38 using System.Collections;
39 using System.ComponentModel;
40 using System.Runtime.InteropServices;
41 using System.Runtime.Serialization;
42
43 namespace System.Data {
44         [Serializable]
45         internal delegate void DelegateConstraintNameChange (object sender, string newName);
46
47         [DefaultProperty ("ConstraintName")]    
48         [Serializable]
49         [TypeConverterAttribute (typeof (ConstraintConverter))]
50         public abstract class Constraint 
51         {
52                 internal event DelegateConstraintNameChange BeforeConstraintNameChange;
53
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;
61
62                 private Index _index;
63
64                 //Used for membership checking
65                 private ConstraintCollection _constraintCollection;
66
67                 DataSet dataSet;
68
69                 protected Constraint () 
70                 {
71                         dataSet = null;
72                         _properties = new PropertyCollection();
73                 }
74
75                 [CLSCompliant (false)]
76                 protected internal virtual DataSet _DataSet {
77                         get { return dataSet; }
78                 }
79
80                 [DataCategory ("Data")]
81                 [DataSysDescription ("Indicates the name of this constraint.")]
82                 [DefaultValue ("")]
83                 public virtual string ConstraintName {
84                         get{ return _constraintName == null ? "" : _constraintName; } 
85                         set{
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;
92                         }
93                 }
94
95                 [Browsable (false)]
96                 [DataCategory ("Data")]
97                 [DataSysDescription ("The collection that holds custom user information.")]
98                 public PropertyCollection ExtendedProperties {
99                         get { return _properties; }
100                 }
101
102                 [DataSysDescription ("Indicates the table of this constraint.")]
103                 public abstract DataTable Table {
104                         get;
105                 }
106
107                 internal ConstraintCollection ConstraintCollection {
108                         get{ return _constraintCollection; }
109                         set{ _constraintCollection = value; }
110                 }
111                 
112                 private void _onConstraintNameChange (string newName)
113                 {
114                         if (null != BeforeConstraintNameChange)
115                         {
116                                 BeforeConstraintNameChange (this, newName);
117                         }
118                 }
119
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)
123                 {
124                 }
125                                         
126                 internal virtual void AssertConstraint ()
127                 {
128                 }
129                 
130                 internal virtual void AssertConstraint (DataRow row)
131                 {
132                 }
133
134                 internal virtual void RollbackAssert (DataRow row)
135                 {
136                 }
137
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)
141                 {
142                 }
143
144                 [MonoTODO]
145                 protected void CheckStateForProperty ()
146                 {
147                         throw new NotImplementedException ();
148                 }
149
150                 protected internal void SetDataSet (DataSet dataSet)
151                 {
152                         this.dataSet = dataSet;
153                 }
154
155                 internal Index Index
156                 {
157                         get {
158                                 return _index;
159                         }
160                         set {
161                                 _index = value;
162                         }
163                 }
164
165                 internal void UpdateIndex (DataRow row)
166                 {
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]) {
174                                                 keyChanged = true;
175                                         }
176                                 }
177                                 // if key changed we first try to insert a new node 
178                                 // and,if succeded, we delete the row's old node.
179                                 if (keyChanged) 
180                                 {
181                                         // insert new node for the row
182                                         // note : may throw if not succeded
183                                         Index.Insert (new Node (row), DataRowVersion.Default);
184
185                                         // delete the row's node
186                                         Index.Delete(row);                                      
187                                 }
188                         }
189                 }
190
191                 internal void RollbackIndex (DataRow row)
192                 {
193                         Node n = Index.Find(row, DataRowVersion.Default);
194                         if ( n == null)
195                                 throw new ConstraintException("Row was not found in constraint index");
196
197                         // first remove the node inserted as a result of last AssertConstraint on the row 
198                         Index.Delete(n);
199                         
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);
206                         }
207                 }
208
209
210                 /// <summary>
211                 /// Gets the ConstraintName, if there is one, as a string. 
212                 /// </summary>
213                 public override string ToString () 
214                 {
215                         return _constraintName == null ? "" : _constraintName;
216                 }
217
218         }
219 }