| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410 |
- //------------------------------------------------------------------------------
- // <copyright file="UniqueConstraint.cs" company="Microsoft">
- // Copyright (c) Microsoft Corporation. All rights reserved.
- // </copyright>
- // <owner current="true" primary="true">[....]</owner>
- // <owner current="true" primary="false">[....]</owner>
- // <owner current="false" primary="false">[....]</owner>
- //------------------------------------------------------------------------------
- namespace System.Data {
- using System;
- using System.Diagnostics;
- using System.ComponentModel;
- /// <devdoc>
- /// <para>
- /// Represents a restriction on a set of columns in which all values must be unique.
- /// </para>
- /// </devdoc>
- [
- DefaultProperty("ConstraintName"),
- Editor("Microsoft.VSDesigner.Data.Design.UniqueConstraintEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
- ]
- public class UniqueConstraint : Constraint {
- private DataKey key;
- private Index _constraintIndex;
- internal bool bPrimaryKey = false;
- // Design time serialization
- internal string constraintName = null;
- internal string[] columnNames = null;
- /// <devdoc>
- /// <para>Initializes a new instance of the <see cref='System.Data.UniqueConstraint'/> with the specified name and
- /// <see cref='System.Data.DataColumn'/>.</para>
- /// </devdoc>
- public UniqueConstraint(String name, DataColumn column) {
- DataColumn[] columns = new DataColumn[1];
- columns[0] = column;
- Create(name, columns);
- }
- /// <devdoc>
- /// <para>Initializes a new instance of the <see cref='System.Data.UniqueConstraint'/> with the specified <see cref='System.Data.DataColumn'/>.</para>
- /// </devdoc>
- public UniqueConstraint(DataColumn column) {
- DataColumn[] columns = new DataColumn[1];
- columns[0] = column;
- Create(null, columns);
- }
- /// <devdoc>
- /// <para>Initializes a new instance of the <see cref='System.Data.UniqueConstraint'/> with the specified name and array
- /// of <see cref='System.Data.DataColumn'/> objects.</para>
- /// </devdoc>
- public UniqueConstraint(String name, DataColumn[] columns) {
- Create(name, columns);
- }
- /// <devdoc>
- /// <para>
- /// Initializes a new instance of the <see cref='System.Data.UniqueConstraint'/> with the given array of <see cref='System.Data.DataColumn'/>
- /// objects.
- /// </para>
- /// </devdoc>
- public UniqueConstraint(DataColumn[] columns) {
- Create(null, columns);
- }
- // Construct design time object
- /// <devdoc>
- /// <para>[To be supplied.]</para>
- /// </devdoc>
- [Browsable(false)]
- public UniqueConstraint(String name, string[] columnNames, bool isPrimaryKey) {
- this.constraintName = name;
- this.columnNames = columnNames;
- this.bPrimaryKey = isPrimaryKey;
- }
- /// <devdoc>
- /// <para>Initializes a new instance of the <see cref='System.Data.UniqueConstraint'/> with the specified name and
- /// <see cref='System.Data.DataColumn'/>.</para>
- /// </devdoc>
- public UniqueConstraint(String name, DataColumn column, bool isPrimaryKey) {
- DataColumn[] columns = new DataColumn[1];
- columns[0] = column;
- this.bPrimaryKey = isPrimaryKey;
- Create(name, columns);
- }
- /// <devdoc>
- /// <para>Initializes a new instance of the <see cref='System.Data.UniqueConstraint'/> with the specified <see cref='System.Data.DataColumn'/>.</para>
- /// </devdoc>
- public UniqueConstraint(DataColumn column, bool isPrimaryKey) {
- DataColumn[] columns = new DataColumn[1];
- columns[0] = column;
- this.bPrimaryKey = isPrimaryKey;
- Create(null, columns);
- }
- /// <devdoc>
- /// <para>Initializes a new instance of the <see cref='System.Data.UniqueConstraint'/> with the specified name and array
- /// of <see cref='System.Data.DataColumn'/> objects.</para>
- /// </devdoc>
- public UniqueConstraint(String name, DataColumn[] columns, bool isPrimaryKey) {
- this.bPrimaryKey = isPrimaryKey;
- Create(name, columns);
- }
- /// <devdoc>
- /// <para>
- /// Initializes a new instance of the <see cref='System.Data.UniqueConstraint'/> with the given array of <see cref='System.Data.DataColumn'/>
- /// objects.
- /// </para>
- /// </devdoc>
- public UniqueConstraint(DataColumn[] columns, bool isPrimaryKey) {
- this.bPrimaryKey = isPrimaryKey;
- Create(null, columns);
- }
- // design time serialization only
- internal string[] ColumnNames {
- get {
- return key.GetColumnNames();
- }
- }
- // VSTFDEVDIV 895693: please note that there are scenarios where ConstraintIndex is not the same as key.GetSortIndex()
- // Use constraint index only for search operations (and use key.GetSortIndex() when enumeration is needed and/or order is important)
- internal Index ConstraintIndex {
- get {
- AssertConstraintAndKeyIndexes();
- return _constraintIndex;
- }
- }
- [Conditional("DEBUG")]
- private void AssertConstraintAndKeyIndexes() {
- Debug.Assert(null != _constraintIndex, "null UniqueConstraint index");
- // ideally, we would like constraintIndex and key.GetSortIndex to share the same index underneath: Debug.Assert(_constraintIndex == key.GetSortIndex)
- // but, due to VSTFDEVDIV #895693 there is a scenario where constraint and key indexes are built from the same list of columns but in a different order
- DataColumn[] sortIndexColumns = new DataColumn[_constraintIndex.IndexFields.Length];
- for (int i = 0; i < sortIndexColumns.Length; i++) {
- sortIndexColumns[i] = _constraintIndex.IndexFields[i].Column;
- }
- Debug.Assert(DataKey.ColumnsEqual(key.ColumnsReference, sortIndexColumns), "UniqueConstraint index columns do not match the key sort index");
- }
- internal void ConstraintIndexClear() {
- if (null != _constraintIndex) {
- _constraintIndex.RemoveRef();
- _constraintIndex = null;
- }
- }
-
- internal void ConstraintIndexInitialize() {
- //Debug.Assert(null == _constraintIndex, "non-null UniqueConstraint index");
- if (null == _constraintIndex) {
- _constraintIndex = key.GetSortIndex();
- _constraintIndex.AddRef();
- }
- AssertConstraintAndKeyIndexes();
- }
- internal override void CheckState() {
- NonVirtualCheckState();
- }
- private void NonVirtualCheckState() {
- key.CheckState();
- }
- internal override void CheckCanAddToCollection(ConstraintCollection constraints) {
- }
- internal override bool CanBeRemovedFromCollection(ConstraintCollection constraints, bool fThrowException) {
- if (this.Equals(constraints.Table.primaryKey)) {
- Debug.Assert(constraints.Table.primaryKey == this, "If the primary key and this are 'Equal', they should also be '=='");
- if (!fThrowException)
- return false;
- else
- throw ExceptionBuilder.RemovePrimaryKey(constraints.Table);
- }
- for (ParentForeignKeyConstraintEnumerator cs = new ParentForeignKeyConstraintEnumerator(Table.DataSet, Table); cs.GetNext();) {
- ForeignKeyConstraint constraint = cs.GetForeignKeyConstraint();
- if (!key.ColumnsEqual(constraint.ParentKey))
- continue;
- if (!fThrowException)
- return false;
- else
- throw ExceptionBuilder.NeededForForeignKeyConstraint(this, constraint);
- }
- return true;
- }
- internal override bool CanEnableConstraint() {
- if (Table.EnforceConstraints)
- return ConstraintIndex.CheckUnique();
- return true;
- }
- internal override bool IsConstraintViolated() {
- bool result = false;
- Index index = ConstraintIndex;
- if (index.HasDuplicates) {
- //
- object[] uniqueKeys = index.GetUniqueKeyValues();
- for (int i = 0; i < uniqueKeys.Length; i++) {
- Range r = index.FindRecords((object[])uniqueKeys[i]);
- if (1 < r.Count) {
- DataRow[] rows = index.GetRows(r);
- string error = ExceptionBuilder.UniqueConstraintViolationText(key.ColumnsReference, (object[])uniqueKeys[i]);
- for (int j = 0; j < rows.Length; j++) {
- //
- rows[j].RowError = error;
- foreach(DataColumn dataColumn in key.ColumnsReference){
- rows[j].SetColumnError(dataColumn, error);
- }
- }
- // SQLBU 20011224: set_RowError for all DataRow with a unique constraint violation
- result = true;
- }
- }
- }
- return result;
- }
- internal override void CheckConstraint(DataRow row, DataRowAction action) {
- if (Table.EnforceConstraints &&
- (action == DataRowAction.Add ||
- action == DataRowAction.Change ||
- (action == DataRowAction.Rollback && row.tempRecord != -1))) {
- if (row.HaveValuesChanged(ColumnsReference)) {
- if (ConstraintIndex.IsKeyRecordInIndex(row.GetDefaultRecord())) {
- object[] values = row.GetColumnValues(ColumnsReference);
- throw ExceptionBuilder.ConstraintViolation(ColumnsReference, values);
- }
- }
- }
- }
- internal override bool ContainsColumn(DataColumn column) {
- return key.ContainsColumn(column);
- }
- internal override Constraint Clone(DataSet destination) {
- return Clone(destination, false);
- }
- internal override Constraint Clone(DataSet destination, bool ignorNSforTableLookup) {
- int iDest;
- if (ignorNSforTableLookup) {
- iDest = destination.Tables.IndexOf(Table.TableName);
- }
- else {
- iDest = destination.Tables.IndexOf(Table.TableName, Table.Namespace, false);// pass false for last param to be backward compatable
- }
- if (iDest < 0)
- return null;
- DataTable table = destination.Tables[iDest];
- int keys = ColumnsReference.Length;
- DataColumn[] columns = new DataColumn[keys];
- for (int i = 0; i < keys; i++) {
- DataColumn src = ColumnsReference[i];
- iDest = table.Columns.IndexOf(src.ColumnName);
- if (iDest < 0)
- return null;
- columns[i] = table.Columns[iDest];
- }
- UniqueConstraint clone = new UniqueConstraint(ConstraintName, columns);
- // ...Extended Properties
- foreach(Object key in this.ExtendedProperties.Keys) {
- clone.ExtendedProperties[key]=this.ExtendedProperties[key];
- }
- return clone;
- }
- internal UniqueConstraint Clone(DataTable table) {
- int keys = ColumnsReference.Length;
- DataColumn[] columns = new DataColumn[keys];
- for (int i = 0; i < keys; i++) {
- DataColumn src = ColumnsReference[i];
- int iDest = table.Columns.IndexOf(src.ColumnName);
- if (iDest < 0)
- return null;
- columns[i] = table.Columns[iDest];
- }
- UniqueConstraint clone = new UniqueConstraint(ConstraintName, columns);
- // ...Extended Properties
- foreach(Object key in this.ExtendedProperties.Keys) {
- clone.ExtendedProperties[key]=this.ExtendedProperties[key];
- }
- return clone;
- }
- /// <devdoc>
- /// <para>Gets the array of columns that this constraint affects.</para>
- /// </devdoc>
- [
- ResCategoryAttribute(Res.DataCategory_Data),
- ResDescriptionAttribute(Res.KeyConstraintColumnsDescr),
- ReadOnly(true)
- ]
- public virtual DataColumn[] Columns {
- get {
- return key.ToArray();
- }
- }
- internal DataColumn[] ColumnsReference {
- get {
- return key.ColumnsReference;
- }
- }
- /// <devdoc>
- /// <para>Gets
- /// a value indicating whether or not the constraint is on a primary key.</para>
- /// </devdoc>
- [
- ResCategoryAttribute(Res.DataCategory_Data),
- ResDescriptionAttribute(Res.KeyConstraintIsPrimaryKeyDescr)
- ]
- public bool IsPrimaryKey {
- get {
- if (Table == null) {
- return false;
- }
- return(this == Table.primaryKey);
- }
- }
- private void Create(String constraintName, DataColumn[] columns) {
- for (int i = 0; i < columns.Length; i++) {
- if (columns[i].Computed) {
- throw ExceptionBuilder.ExpressionInConstraint(columns[i]);
- }
- }
- this.key = new DataKey(columns, true);
- ConstraintName = constraintName;
- NonVirtualCheckState();
- }
- /// <devdoc>
- /// <para>Compares this constraint to a second to
- /// determine if both are identical.</para>
- /// </devdoc>
- public override bool Equals(object key2) {
- if (!(key2 is UniqueConstraint))
- return false;
- return Key.ColumnsEqual(((UniqueConstraint)key2).Key);
- }
- public override Int32 GetHashCode() {
- return base.GetHashCode();
- }
- internal override bool InCollection {
- set {
- base.InCollection = value;
- if (key.ColumnsReference.Length == 1) {
- key.ColumnsReference[0].InternalUnique(value);
- }
- }
- }
- internal DataKey Key {
- get {
- return key;
- }
- }
- /// <devdoc>
- /// <para>Gets the table to which this constraint belongs.</para>
- /// </devdoc>
- [
- ResCategoryAttribute(Res.DataCategory_Data),
- ResDescriptionAttribute(Res.ConstraintTableDescr),
- ReadOnly(true)
- ]
- public override DataTable Table {
- get {
- if (key.HasValue) {
- return key.Table;
- }
- return null;
- }
- }
- // misc
- }
- }
|