1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Diagnostics; 6 7 namespace System.Data 8 { 9 internal readonly struct DataKey 10 { 11 private const int maxColumns = 32; 12 13 private readonly DataColumn[] _columns; 14 DataKeySystem.Data.DataKey15 internal DataKey(DataColumn[] columns, bool copyColumns) 16 { 17 if (columns == null) 18 { 19 throw ExceptionBuilder.ArgumentNull(nameof(columns)); 20 } 21 22 if (columns.Length == 0) 23 { 24 throw ExceptionBuilder.KeyNoColumns(); 25 } 26 27 if (columns.Length > maxColumns) 28 { 29 throw ExceptionBuilder.KeyTooManyColumns(maxColumns); 30 } 31 32 for (int i = 0; i < columns.Length; i++) 33 { 34 if (columns[i] == null) 35 { 36 throw ExceptionBuilder.ArgumentNull("column"); 37 } 38 } 39 40 for (int i = 0; i < columns.Length; i++) 41 { 42 for (int j = 0; j < i; j++) 43 { 44 if (columns[i] == columns[j]) 45 { 46 throw ExceptionBuilder.KeyDuplicateColumns(columns[i].ColumnName); 47 } 48 } 49 } 50 51 if (copyColumns) 52 { 53 // Need to make a copy of all columns 54 _columns = new DataColumn[columns.Length]; 55 for (int i = 0; i < columns.Length; i++) 56 { 57 _columns[i] = columns[i]; 58 } 59 } 60 else 61 { 62 // take ownership of the array passed in 63 _columns = columns; 64 } 65 CheckState(); 66 } 67 68 internal DataColumn[] ColumnsReference => _columns; 69 internal bool HasValue => null != _columns; 70 internal DataTable Table => _columns[0].Table; CheckStateSystem.Data.DataKey71 internal void CheckState() 72 { 73 DataTable table = _columns[0].Table; 74 75 if (table == null) 76 { 77 throw ExceptionBuilder.ColumnNotInAnyTable(); 78 } 79 80 for (int i = 1; i < _columns.Length; i++) 81 { 82 if (_columns[i].Table == null) 83 { 84 throw ExceptionBuilder.ColumnNotInAnyTable(); 85 } 86 if (_columns[i].Table != table) 87 { 88 throw ExceptionBuilder.KeyTableMismatch(); 89 } 90 } 91 } 92 93 //check to see if this.columns && key2's columns are equal regardless of order 94 internal bool ColumnsEqual(DataKey key) => ColumnsEqual(_columns, key._columns); 95 96 //check to see if columns1 && columns2 are equal regardless of order ColumnsEqualSystem.Data.DataKey97 internal static bool ColumnsEqual(DataColumn[] column1, DataColumn[] column2) 98 { 99 if (column1 == column2) 100 { 101 return true; 102 } 103 else if (column1 == null || column2 == null) 104 { 105 return false; 106 } 107 else if (column1.Length != column2.Length) 108 { 109 return false; 110 } 111 else 112 { 113 int i, j; 114 for (i = 0; i < column1.Length; i++) 115 { 116 bool check = false; 117 for (j = 0; j < column2.Length; j++) 118 { 119 if (column1[i].Equals(column2[j])) 120 { 121 check = true; 122 break; 123 } 124 } 125 if (!check) 126 { 127 return false; 128 } 129 } 130 } 131 return true; 132 } 133 ContainsColumnSystem.Data.DataKey134 internal bool ContainsColumn(DataColumn column) 135 { 136 for (int i = 0; i < _columns.Length; i++) 137 { 138 if (column == _columns[i]) 139 { 140 return true; 141 } 142 } 143 return false; 144 } 145 GetHashCodeSystem.Data.DataKey146 public override int GetHashCode() 147 { 148 Debug.Assert(false, "don't put DataKey into a Hashtable"); 149 return base.GetHashCode(); 150 } 151 EqualsSystem.Data.DataKey152 public override bool Equals(object value) 153 { 154 Debug.Assert(false, "need to directly call Equals(DataKey)"); 155 return Equals((DataKey)value); 156 } 157 EqualsSystem.Data.DataKey158 internal bool Equals(DataKey value) 159 { 160 //check to see if this.columns && key2's columns are equal... 161 DataColumn[] column1 = _columns; 162 DataColumn[] column2 = value._columns; 163 164 if (column1 == column2) 165 { 166 return true; 167 } 168 else if (column1 == null || column2 == null) 169 { 170 return false; 171 } 172 else if (column1.Length != column2.Length) 173 { 174 return false; 175 } 176 else 177 { 178 for (int i = 0; i < column1.Length; i++) 179 { 180 if (!column1[i].Equals(column2[i])) 181 { 182 return false; 183 } 184 } 185 return true; 186 } 187 } 188 GetColumnNamesSystem.Data.DataKey189 internal string[] GetColumnNames() 190 { 191 string[] values = new string[_columns.Length]; 192 for (int i = 0; i < _columns.Length; ++i) 193 { 194 values[i] = _columns[i].ColumnName; 195 } 196 return values; 197 } 198 GetIndexDescSystem.Data.DataKey199 internal IndexField[] GetIndexDesc() 200 { 201 IndexField[] indexDesc = new IndexField[_columns.Length]; 202 for (int i = 0; i < _columns.Length; i++) 203 { 204 indexDesc[i] = new IndexField(_columns[i], false); 205 } 206 return indexDesc; 207 } 208 GetKeyValuesSystem.Data.DataKey209 internal object[] GetKeyValues(int record) 210 { 211 object[] values = new object[_columns.Length]; 212 for (int i = 0; i < _columns.Length; i++) 213 { 214 values[i] = _columns[i][record]; 215 } 216 return values; 217 } 218 GetSortIndexSystem.Data.DataKey219 internal Index GetSortIndex() => GetSortIndex(DataViewRowState.CurrentRows); 220 GetSortIndexSystem.Data.DataKey221 internal Index GetSortIndex(DataViewRowState recordStates) 222 { 223 IndexField[] indexDesc = GetIndexDesc(); 224 return _columns[0].Table.GetIndex(indexDesc, recordStates, null); 225 } 226 RecordsEqualSystem.Data.DataKey227 internal bool RecordsEqual(int record1, int record2) 228 { 229 for (int i = 0; i < _columns.Length; i++) 230 { 231 if (_columns[i].Compare(record1, record2) != 0) 232 { 233 return false; 234 } 235 } 236 return true; 237 } 238 ToArraySystem.Data.DataKey239 internal DataColumn[] ToArray() 240 { 241 DataColumn[] values = new DataColumn[_columns.Length]; 242 for (int i = 0; i < _columns.Length; ++i) 243 { 244 values[i] = _columns[i]; 245 } 246 return values; 247 } 248 } 249 } 250