2004-03-03 Atsushi Enomoto <atsushi@ximian.com>
[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 using System;
15 using System.Collections;
16 using System.ComponentModel;
17 using System.Runtime.InteropServices;
18 using System.Runtime.Serialization;
19
20 namespace System.Data {
21         [Serializable]
22         internal delegate void DelegateConstraintNameChange (object sender, string newName);
23
24         [DefaultProperty ("ConstraintName")]    
25         [Serializable]
26         public abstract class Constraint 
27         {
28                 internal event DelegateConstraintNameChange BeforeConstraintNameChange;
29
30                 //if constraintName is not set then a name is 
31                 //created when it is added to
32                 //the ConstraintCollection
33                 //it can not be set to null, empty or duplicate
34                 //once it has been added to the collection
35                 private string _constraintName;
36                 private PropertyCollection _properties;
37
38                 private Index _index;
39
40                 //Used for membership checking
41                 private ConstraintCollection _constraintCollection;
42
43                 DataSet dataSet;
44
45                 protected Constraint () 
46                 {
47                         dataSet = null;
48                         _properties = new PropertyCollection();
49                 }
50
51                 protected internal virtual DataSet _DataSet {
52                         get { return dataSet; }
53                 }
54
55                 [DataCategory ("Data")]
56                 [DataSysDescription ("Indicates the name of this constraint.")]
57                 [DefaultValue ("")]
58                 public virtual string ConstraintName {
59                         get{ return "" + _constraintName; } 
60                         set{
61                                 //This should only throw an exception when it
62                                 //is a member of a ConstraintCollection which
63                                 //means we should let the ConstraintCollection
64                                 //handle exceptions when this value changes
65                                 _onConstraintNameChange(value);
66                                 _constraintName = value;
67                         }
68                 }
69
70                 [Browsable (false)]
71                 [DataCategory ("Data")]
72                 [DataSysDescription ("The collection that holds custom user information.")]
73                 public PropertyCollection ExtendedProperties {
74                         get { return _properties; }
75                 }
76
77                 [DataSysDescription ("Indicates the table of this constraint.")]
78                 public abstract DataTable Table {
79                         get;
80                 }
81
82                 internal ConstraintCollection ConstraintCollection {
83                         get{ return _constraintCollection; }
84                         set{ _constraintCollection = value; }
85                 }
86                 
87                 private void _onConstraintNameChange (string newName)
88                 {
89                         if (null != BeforeConstraintNameChange)
90                         {
91                                 BeforeConstraintNameChange (this, newName);
92                         }
93                 }
94
95                 //call once before adding a constraint to a collection
96                 //will throw an exception to prevent the add if a rule is broken
97                 internal virtual void AddToConstraintCollectionSetup (ConstraintCollection collection)
98                 {
99                 }
100                                         
101                 internal virtual void AssertConstraint ()
102                 {
103                 }
104                 
105                 internal virtual void AssertConstraint (DataRow row)
106                 {
107                 }
108
109                 internal virtual void RollbackAssert (DataRow row)
110                 {
111                 }
112
113                 //call once before removing a constraint to a collection
114                 //can throw an exception to prevent the removal
115                 internal virtual void RemoveFromConstraintCollectionCleanup (ConstraintCollection collection)
116                 {
117                 }
118
119                 [MonoTODO]
120                 protected void CheckStateForProperty ()
121                 {
122                         throw new NotImplementedException ();
123                 }
124
125                 protected internal void SetDataSet (DataSet dataSet)
126                 {
127                         this.dataSet = dataSet;
128                 }
129
130                 internal Index Index
131                 {
132                         get {
133                                 return _index;
134                         }
135                         set {
136                                 _index = value;
137                         }
138                 }
139
140                 protected internal void UpdateIndex (DataRow row)
141                 {
142                         if (row.RowState == DataRowState.Detached || row.RowState == DataRowState.Unchanged)
143                                 Index.Insert (new Node (row), DataRowVersion.Default);
144                         else if ((row.RowState == DataRowState.Modified) || (row.RowState == DataRowState.Added)) {
145                                 // first we check if the values of the key changed.
146                                 bool keyChanged = false;
147                                 for (int i = 0; i < Index.Columns.Length; i++) {
148                                         if (row[Index.Columns[i], DataRowVersion.Default] != row[Index.Columns[i], DataRowVersion.Current]) {
149                                                 keyChanged = true;
150                                         }
151                                 }
152                                 // if key changed we first try to insert a new node 
153                                 // and,if succeded, we delete the row's old node.
154                                 if (keyChanged) 
155                                 {
156                                         // insert new node for the row
157                                         // note : may throw if not succeded
158                                         Index.Insert (new Node (row), DataRowVersion.Default);
159
160                                         // delete the row's node
161                                         Index.Delete(row);                                      
162                                 }
163                         }
164                 }
165
166                 protected internal void RollbackIndex (DataRow row)
167                 {
168                         Node n = Index.Find(row, DataRowVersion.Default);
169                         if ( n == null)
170                                 throw new ConstraintException("Row was not found in constraint index");
171
172                         // first remove the node inserted as a result of last AssertConstraint on the row 
173                         Index.Delete(n);
174                         
175                         // if the row is not detached we should add back to the index 
176                         // node corresponding to row value before AssertConstraint was called
177                         if(row.RowState != DataRowState.Detached){
178                                 // since index before we updated index was ok, insert should always suceed
179                                 // maybe we still need to try/catch here
180                                 Index.Insert(new Node(row), DataRowVersion.Current);
181                         }
182                 }
183
184
185                 /// <summary>
186                 /// Gets the ConstraintName, if there is one, as a string. 
187                 /// </summary>
188                 public override string ToString () 
189                 {
190                         return "" + _constraintName;
191                 }
192
193         }
194 }