DataColumn.cs 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473
  1. //
  2. // System.Data.DataColumn.cs
  3. //
  4. // Author:
  5. // Franklin Wise ([email protected])
  6. // Christopher Podurgiel ([email protected])
  7. // Rodrigo Moya ([email protected])
  8. // Daniel Morgan ([email protected])
  9. //
  10. // (C) Copyright 2002, Franklin Wise
  11. // (C) Chris Podurgiel
  12. // (C) Ximian, Inc 2002
  13. // (C) Daniel Morgan 2002
  14. //
  15. using System;
  16. using System.ComponentModel;
  17. namespace System.Data
  18. {
  19. internal delegate void DelegateColumnValueChange(DataColumn column,
  20. DataRow row, object proposedValue);
  21. /// <summary>
  22. /// Summary description for DataColumn.
  23. /// </summary>
  24. public class DataColumn : MarshalByValueComponent
  25. {
  26. #region Events
  27. [MonoTODO]
  28. //used for constraint validation
  29. //if an exception is fired during this event the change should be canceled
  30. internal event DelegateColumnValueChange ValidateColumnValueChange;
  31. //used for FK Constraint Cascading rules
  32. internal event DelegateColumnValueChange ColumnValueChanging;
  33. #endregion //Events
  34. #region Fields
  35. private bool _allowDBNull = true;
  36. private bool _autoIncrement = false;
  37. private long _autoIncrementSeed = 0;
  38. private long _autoIncrementStep = 1;
  39. private string _caption = null;
  40. private MappingType _columnMapping = MappingType.Element;
  41. private string _columnName = null;
  42. private Type _dataType = null;
  43. private object _defaultValue = null;
  44. private string expression = null;
  45. private PropertyCollection _extendedProperties = null;
  46. private int maxLength = -1; //-1 represents no length limit
  47. private string nameSpace = null;
  48. private int _ordinal = -1; //-1 represents not part of a collection
  49. private string prefix = null;
  50. private bool readOnly = false;
  51. private DataTable _table = null;
  52. private bool unique = false;
  53. #endregion // Fields
  54. #region Constructors
  55. public DataColumn()
  56. {
  57. }
  58. //TODO: Ctor init vars directly
  59. public DataColumn(string columnName): this()
  60. {
  61. ColumnName = columnName;
  62. }
  63. public DataColumn(string columnName, Type dataType): this(columnName)
  64. {
  65. if(dataType == null) {
  66. throw new ArgumentNullException("dataType can't be null.");
  67. }
  68. DataType = dataType;
  69. }
  70. public DataColumn( string columnName, Type dataType,
  71. string expr): this(columnName, dataType)
  72. {
  73. Expression = expr;
  74. }
  75. public DataColumn(string columnName, Type dataType,
  76. string expr, MappingType type): this(columnName, dataType, expr)
  77. {
  78. ColumnMapping = type;
  79. }
  80. #endregion
  81. #region Properties
  82. public bool AllowDBNull
  83. {
  84. get {
  85. return _allowDBNull;
  86. }
  87. set {
  88. //TODO: If we are a part of the table and this value changes
  89. //we need to validate that all the existing values conform to the new setting
  90. if (true == value)
  91. {
  92. _allowDBNull = true;
  93. return;
  94. }
  95. //if Value == false case
  96. if (null != _table)
  97. {
  98. if (_table.Rows.Count > 0)
  99. {
  100. //TODO: Validate no null values exist
  101. //do we also check different versions of the row??
  102. }
  103. }
  104. _allowDBNull = value;
  105. }
  106. }
  107. /// <summary>
  108. /// Gets or sets a value indicating whether the column automatically increments the value of the column for new rows added to the table.
  109. /// </summary>
  110. /// <remarks>
  111. /// If the type of this column is not Int16, Int32, or Int64 when this property is set,
  112. /// the DataType property is coerced to Int32. An exception is generated if this is a computed column
  113. /// (that is, the Expression property is set.) The incremented value is used only if the row's value for this column,
  114. /// when added to the columns collection, is equal to the default value.
  115. /// </remarks>
  116. public bool AutoIncrement
  117. {
  118. get {
  119. return _autoIncrement;
  120. }
  121. set {
  122. if(value == true)
  123. {
  124. //Can't be true if this is a computed column
  125. if(Expression != null)
  126. {
  127. throw new ArgumentException("Can't Auto Increment a computed column.");
  128. }
  129. //If the DataType of this Column isn't an Int
  130. //Make it an int
  131. if(Type.GetTypeCode(_dataType) != TypeCode.Int16 &&
  132. Type.GetTypeCode(_dataType) != TypeCode.Int32 &&
  133. Type.GetTypeCode(_dataType) != TypeCode.Int64)
  134. {
  135. _dataType = typeof(Int32);
  136. }
  137. }
  138. _autoIncrement = value;
  139. }
  140. }
  141. public long AutoIncrementSeed
  142. {
  143. get {
  144. return _autoIncrementSeed;
  145. }
  146. set {
  147. _autoIncrementSeed = value;
  148. }
  149. }
  150. public long AutoIncrementStep
  151. {
  152. get {
  153. return _autoIncrementStep;
  154. }
  155. set {
  156. _autoIncrementStep = value;
  157. }
  158. }
  159. public string Caption
  160. {
  161. get {
  162. if(_caption == null)
  163. return ColumnName;
  164. else
  165. return _caption;
  166. }
  167. set {
  168. _caption = value;
  169. }
  170. }
  171. public virtual MappingType ColumnMapping
  172. {
  173. get {
  174. return _columnMapping;
  175. }
  176. set {
  177. _columnMapping = value;
  178. }
  179. }
  180. public string ColumnName
  181. {
  182. get {
  183. return "" + _columnName;
  184. }
  185. set {
  186. //Both are checked after the column is part of the collection
  187. //TODO: Check Name duplicate
  188. //TODO: check Name != null
  189. _columnName = value;
  190. }
  191. }
  192. public Type DataType
  193. {
  194. get {
  195. return _dataType;
  196. }
  197. set {
  198. //TODO: check if data already exists can we change the datatype
  199. //TODO: we want to check that the datatype is supported?
  200. //Check AutoIncrement status, make compatible datatype
  201. //TODO: Check for other int values i.e. Int16 etc
  202. if(AutoIncrement == true &&
  203. Type.GetTypeCode(value) != TypeCode.Int32)
  204. {
  205. throw new Exception(); //TODO: correction exception type
  206. }
  207. _dataType = value;
  208. }
  209. }
  210. /// <summary>
  211. ///
  212. /// </summary>
  213. /// <remarks>When AutoIncrement is set to true, there can be no default value.</remarks>
  214. /// <exception cref="System.InvalidCastException"></exception>
  215. /// <exception cref="System.ArgumentException"></exception>
  216. public object DefaultValue
  217. {
  218. get {
  219. return _defaultValue;
  220. }
  221. set {
  222. //If autoIncrement == true throw
  223. if (AutoIncrement)
  224. {
  225. throw new ArgumentException("Can not set default value while" +
  226. " AutoIncrement is true on this column.");
  227. }
  228. //Will throw invalid cast exception
  229. //if value is not the correct type
  230. //FIXME: some types can be casted
  231. if (value.GetType() != _dataType)
  232. {
  233. throw new InvalidCastException("Default Value type is not compatible with" +
  234. " column type.");
  235. }
  236. _defaultValue = value;
  237. }
  238. }
  239. [MonoTODO]
  240. public string Expression
  241. {
  242. get {
  243. return expression;
  244. }
  245. set {
  246. //TODO: validation of the expression
  247. expression = value; //Check?
  248. }
  249. }
  250. public PropertyCollection ExtendedProperties
  251. {
  252. get {
  253. return _extendedProperties;
  254. }
  255. }
  256. public int MaxLength
  257. {
  258. get {
  259. //Default == -1 no max length
  260. return maxLength;
  261. }
  262. set {
  263. //only applies to string columns
  264. maxLength = value;
  265. }
  266. }
  267. public string Namespace
  268. {
  269. get {
  270. return nameSpace;
  271. }
  272. set {
  273. nameSpace = value;
  274. }
  275. }
  276. //Need a good way to set the Ordinal when the column is added to a columnCollection.
  277. public int Ordinal
  278. {
  279. get {
  280. //value is -1 if not part of a collection
  281. return _ordinal;
  282. }
  283. }
  284. internal void SetOrdinal(int ordinal)
  285. {
  286. _ordinal = ordinal;
  287. }
  288. public string Prefix
  289. {
  290. get {
  291. return prefix;
  292. }
  293. set {
  294. prefix = value;
  295. }
  296. }
  297. public bool ReadOnly
  298. {
  299. get {
  300. return readOnly;
  301. }
  302. set {
  303. readOnly = value;
  304. }
  305. }
  306. public DataTable Table
  307. {
  308. get {
  309. return _table;
  310. }
  311. }
  312. [MonoTODO]
  313. public bool Unique
  314. {
  315. get {
  316. return unique;
  317. }
  318. set {
  319. //if Table == null then the UniqueConstraint is
  320. //created on addition to the collection
  321. //FIXME?: need to check if value is the same
  322. //because when calling "new UniqueConstraint"
  323. //the new object tries to set "column.Unique = True"
  324. //which creates an infinite loop.
  325. if(unique != value)
  326. {
  327. unique = value;
  328. if( value )
  329. {
  330. if( _table != null )
  331. {
  332. UniqueConstraint uc = new UniqueConstraint(this);
  333. _table.Constraints.Add(uc);
  334. }
  335. }
  336. else
  337. {
  338. if( _table != null )
  339. {
  340. //FIXME: Add code to remove constraint from DataTable
  341. throw new NotImplementedException ();
  342. }
  343. }
  344. }
  345. }
  346. }
  347. #endregion // Properties
  348. #region Methods
  349. /* ??
  350. [MonoTODO]
  351. protected internal void CheckNotAllowNull() {
  352. }
  353. [MonoTODO]
  354. protected void CheckUnique() {
  355. }
  356. */
  357. [MonoTODO]
  358. internal void AssertCanAddToCollection()
  359. {
  360. //Check if Default Value is set and AutoInc is set
  361. }
  362. [MonoTODO]
  363. protected internal virtual void
  364. OnPropertyChanging (PropertyChangedEventArgs pcevent) {
  365. }
  366. [MonoTODO]
  367. protected internal void RaisePropertyChanging(string name) {
  368. }
  369. /// <summary>
  370. /// Gets the Expression of the column, if one exists.
  371. /// </summary>
  372. /// <returns>The Expression value, if the property is set;
  373. /// otherwise, the ColumnName property.</returns>
  374. [MonoTODO]
  375. public override string ToString()
  376. {
  377. if (expression != null)
  378. return expression;
  379. return ColumnName;
  380. }
  381. [MonoTODO]
  382. internal void SetTable(DataTable table) {
  383. _table = table;
  384. // this will get called by DataTable
  385. // and DataColumnCollection
  386. }
  387. // Returns true if all the same collumns are in columnSet and compareSet
  388. internal static bool AreColumnSetsTheSame(DataColumn[] columnSet, DataColumn[] compareSet)
  389. {
  390. if (null == columnSet && null == compareSet) return true;
  391. if (null == columnSet || null == compareSet) return false;
  392. if (columnSet.Length != compareSet.Length) return false;
  393. foreach (DataColumn col in columnSet)
  394. {
  395. bool matchFound = false;
  396. foreach (DataColumn compare in compareSet)
  397. {
  398. if (col == compare)
  399. {
  400. matchFound = true;
  401. }
  402. }
  403. if (! matchFound) return false;
  404. }
  405. return true;
  406. }
  407. #endregion // Methods
  408. }
  409. }