e79aa3c0ed
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
737 lines
29 KiB
C#
737 lines
29 KiB
C#
//------------------------------------------------------------------------------
|
|
// <copyright file="ConstraintCollection.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.Collections;
|
|
using System.ComponentModel;
|
|
|
|
/// <devdoc>
|
|
/// <para>Represents a collection of constraints for a <see cref='System.Data.DataTable'/>
|
|
/// .</para>
|
|
/// </devdoc>
|
|
[
|
|
DefaultEvent("CollectionChanged"),
|
|
Editor("Microsoft.VSDesigner.Data.Design.ConstraintsCollectionEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
|
|
]
|
|
public sealed class ConstraintCollection : InternalDataCollectionBase { // WebData 111752
|
|
|
|
private readonly DataTable table;
|
|
// private Constraint[] constraints = new Constraint[2];
|
|
private readonly ArrayList list = new ArrayList();
|
|
private int defaultNameIndex = 1;
|
|
|
|
private CollectionChangeEventHandler onCollectionChanged;
|
|
private Constraint[] delayLoadingConstraints;
|
|
private bool fLoadForeignKeyConstraintsOnly = false;
|
|
|
|
/// <devdoc>
|
|
/// ConstraintCollection constructor. Used only by DataTable.
|
|
/// </devdoc>
|
|
internal ConstraintCollection(DataTable table) {
|
|
this.table = table;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Gets the list of objects contained by the collection.</para>
|
|
/// </devdoc>
|
|
protected override ArrayList List {
|
|
get {
|
|
return list;
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Gets the <see cref='System.Data.Constraint'/>
|
|
/// from the collection at the specified index.</para>
|
|
/// </devdoc>
|
|
public Constraint this[int index] {
|
|
get {
|
|
if (index >= 0 && index < List.Count) {
|
|
return(Constraint) List[index];
|
|
}
|
|
throw ExceptionBuilder.ConstraintOutOfRange(index);
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// The DataTable with which this ConstraintCollection is associated
|
|
/// </devdoc>
|
|
internal DataTable Table {
|
|
get {
|
|
return table;
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Gets the <see cref='System.Data.Constraint'/> from the collection with the specified name.</para>
|
|
/// </devdoc>
|
|
public Constraint this[string name] {
|
|
get {
|
|
int index = InternalIndexOf(name);
|
|
if (index == -2) {
|
|
throw ExceptionBuilder.CaseInsensitiveNameConflict(name);
|
|
}
|
|
return (index < 0) ? null : (Constraint)List[index];
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Adds the constraint to the collection.</para>
|
|
/// </devdoc>
|
|
public void Add(Constraint constraint) {
|
|
Add(constraint, true);
|
|
}
|
|
|
|
// To add foreign key constraint without adding any unique constraint for internal use. Main purpose : Binary Remoting
|
|
internal void Add(Constraint constraint, bool addUniqueWhenAddingForeign) {
|
|
|
|
if (constraint == null)
|
|
throw ExceptionBuilder.ArgumentNull("constraint");
|
|
|
|
// It is an error if we find an equivalent constraint already in collection
|
|
if (FindConstraint(constraint) != null) {
|
|
throw ExceptionBuilder.DuplicateConstraint(FindConstraint(constraint).ConstraintName);
|
|
}
|
|
|
|
if (1 < table.NestedParentRelations.Length) {
|
|
if (!AutoGenerated(constraint)) {
|
|
throw ExceptionBuilder.CantAddConstraintToMultipleNestedTable(table.TableName);
|
|
}
|
|
}
|
|
|
|
if (constraint is UniqueConstraint) {
|
|
if (((UniqueConstraint)constraint).bPrimaryKey) {
|
|
if (Table.primaryKey != null) {
|
|
throw ExceptionBuilder.AddPrimaryKeyConstraint();
|
|
}
|
|
}
|
|
AddUniqueConstraint((UniqueConstraint)constraint);
|
|
}
|
|
else if (constraint is ForeignKeyConstraint) {
|
|
ForeignKeyConstraint fk = (ForeignKeyConstraint)constraint;
|
|
if (addUniqueWhenAddingForeign) {
|
|
UniqueConstraint key = fk.RelatedTable.Constraints.FindKeyConstraint(fk.RelatedColumnsReference);
|
|
if (key == null) {
|
|
if (constraint.ConstraintName.Length == 0)
|
|
constraint.ConstraintName = AssignName();
|
|
else
|
|
RegisterName(constraint.ConstraintName);
|
|
|
|
key = new UniqueConstraint(fk.RelatedColumnsReference);
|
|
fk.RelatedTable.Constraints.Add(key);
|
|
}
|
|
}
|
|
AddForeignKeyConstraint((ForeignKeyConstraint)constraint);
|
|
}
|
|
BaseAdd(constraint);
|
|
ArrayAdd(constraint);
|
|
OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Add, constraint));
|
|
|
|
if (constraint is UniqueConstraint) {
|
|
if (((UniqueConstraint)constraint).bPrimaryKey) {
|
|
Table.PrimaryKey = ((UniqueConstraint)constraint).ColumnsReference;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Constructs a new <see cref='System.Data.UniqueConstraint'/> using the
|
|
/// specified array of <see cref='System.Data.DataColumn'/>
|
|
/// objects and adds it to the collection.</para>
|
|
/// </devdoc>
|
|
public Constraint Add(string name, DataColumn[] columns, bool primaryKey) {
|
|
UniqueConstraint constraint = new UniqueConstraint(name, columns);
|
|
Add(constraint);
|
|
if (primaryKey)
|
|
Table.PrimaryKey = columns;
|
|
return constraint;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Constructs a new <see cref='System.Data.UniqueConstraint'/> using the
|
|
/// specified <see cref='System.Data.DataColumn'/> and adds it to the collection.</para>
|
|
/// </devdoc>
|
|
public Constraint Add(string name, DataColumn column, bool primaryKey) {
|
|
UniqueConstraint constraint = new UniqueConstraint(name, column);
|
|
Add(constraint);
|
|
if (primaryKey)
|
|
Table.PrimaryKey = constraint.ColumnsReference;
|
|
return constraint;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Constructs a new <see cref='System.Data.ForeignKeyConstraint'/>
|
|
/// with the
|
|
/// specified parent and child
|
|
/// columns and adds the constraint to the collection.</para>
|
|
/// </devdoc>
|
|
public Constraint Add(string name, DataColumn primaryKeyColumn, DataColumn foreignKeyColumn) {
|
|
ForeignKeyConstraint constraint = new ForeignKeyConstraint(name, primaryKeyColumn, foreignKeyColumn);
|
|
Add(constraint);
|
|
return constraint;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Constructs a new <see cref='System.Data.ForeignKeyConstraint'/> with the specified parent columns and
|
|
/// child columns and adds the constraint to the collection.</para>
|
|
/// </devdoc>
|
|
public Constraint Add(string name, DataColumn[] primaryKeyColumns, DataColumn[] foreignKeyColumns) {
|
|
ForeignKeyConstraint constraint = new ForeignKeyConstraint(name, primaryKeyColumns, foreignKeyColumns);
|
|
Add(constraint);
|
|
return constraint;
|
|
}
|
|
|
|
public void AddRange(Constraint[] constraints ) {
|
|
if (table.fInitInProgress) {
|
|
delayLoadingConstraints = constraints;
|
|
fLoadForeignKeyConstraintsOnly = false;
|
|
return;
|
|
}
|
|
|
|
if (constraints != null) {
|
|
foreach(Constraint constr in constraints) {
|
|
if (constr != null) {
|
|
Add(constr);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
private void AddUniqueConstraint(UniqueConstraint constraint) {
|
|
DataColumn[] columns = constraint.ColumnsReference;
|
|
|
|
for (int i = 0; i < columns.Length; i++) {
|
|
if (columns[i].Table != this.table) {
|
|
throw ExceptionBuilder.ConstraintForeignTable();
|
|
}
|
|
}
|
|
constraint.ConstraintIndexInitialize();
|
|
|
|
if (!constraint.CanEnableConstraint()) {
|
|
constraint.ConstraintIndexClear();
|
|
throw ExceptionBuilder.UniqueConstraintViolation();
|
|
}
|
|
}
|
|
|
|
private void AddForeignKeyConstraint(ForeignKeyConstraint constraint) {
|
|
if (!constraint.CanEnableConstraint()) {
|
|
throw ExceptionBuilder.ConstraintParentValues();
|
|
}
|
|
constraint.CheckCanAddToCollection(this);
|
|
}
|
|
|
|
private bool AutoGenerated(Constraint constraint) {
|
|
ForeignKeyConstraint fk = (constraint as ForeignKeyConstraint);
|
|
if (null != fk) {
|
|
return XmlTreeGen.AutoGenerated(fk, false);
|
|
}
|
|
else {
|
|
UniqueConstraint unique = (UniqueConstraint) constraint;
|
|
return XmlTreeGen.AutoGenerated(unique);
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Occurs when the <see cref='System.Data.ConstraintCollection'/> is changed through additions or
|
|
/// removals.</para>
|
|
/// </devdoc>
|
|
public event CollectionChangeEventHandler CollectionChanged {
|
|
add {
|
|
onCollectionChanged += value;
|
|
}
|
|
remove {
|
|
onCollectionChanged -= value;
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Adds the constraint to the constraints array.
|
|
/// </devdoc>
|
|
private void ArrayAdd(Constraint constraint) {
|
|
Debug.Assert(constraint != null, "Attempt to add null constraint to constraint array");
|
|
List.Add(constraint);
|
|
}
|
|
|
|
private void ArrayRemove(Constraint constraint) {
|
|
List.Remove(constraint);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Creates a new default name.
|
|
/// </devdoc>
|
|
internal string AssignName() {
|
|
string newName = MakeName(defaultNameIndex);
|
|
defaultNameIndex++;
|
|
return newName;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Does verification on the constraint and it's name.
|
|
/// An ArgumentNullException is thrown if this constraint is null. An ArgumentException is thrown if this constraint
|
|
/// already belongs to this collection, belongs to another collection.
|
|
/// A DuplicateNameException is thrown if this collection already has a constraint with the same
|
|
/// name (case insensitive).
|
|
/// </devdoc>
|
|
private void BaseAdd(Constraint constraint) {
|
|
if (constraint == null)
|
|
throw ExceptionBuilder.ArgumentNull("constraint");
|
|
|
|
if (constraint.ConstraintName.Length == 0)
|
|
constraint.ConstraintName = AssignName();
|
|
else
|
|
RegisterName(constraint.ConstraintName);
|
|
|
|
constraint.InCollection = true;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// BaseGroupSwitch will intelligently remove and add tables from the collection.
|
|
/// </devdoc>
|
|
private void BaseGroupSwitch(Constraint[] oldArray, int oldLength, Constraint[] newArray, int newLength) {
|
|
// We're doing a smart diff of oldArray and newArray to find out what
|
|
// should be removed. We'll pass through oldArray and see if it exists
|
|
// in newArray, and if not, do remove work. newBase is an opt. in case
|
|
// the arrays have similar prefixes.
|
|
int newBase = 0;
|
|
for (int oldCur = 0; oldCur < oldLength; oldCur++) {
|
|
bool found = false;
|
|
for (int newCur = newBase; newCur < newLength; newCur++) {
|
|
if (oldArray[oldCur] == newArray[newCur]) {
|
|
if (newBase == newCur) {
|
|
newBase++;
|
|
}
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!found) {
|
|
// This means it's in oldArray and not newArray. Remove it.
|
|
BaseRemove(oldArray[oldCur]);
|
|
List.Remove(oldArray[oldCur]);
|
|
|
|
}
|
|
}
|
|
|
|
// Now, let's pass through news and those that don't belong, add them.
|
|
for (int newCur = 0; newCur < newLength; newCur++) {
|
|
if (!newArray[newCur].InCollection)
|
|
BaseAdd(newArray[newCur]);
|
|
List.Add(newArray[newCur]);
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Does verification on the constraint and it's name.
|
|
/// An ArgumentNullException is thrown if this constraint is null. An ArgumentException is thrown
|
|
/// if this constraint doesn't belong to this collection or if this constraint is part of a relationship.
|
|
/// </devdoc>
|
|
private void BaseRemove(Constraint constraint) {
|
|
if (constraint == null) {
|
|
throw ExceptionBuilder.ArgumentNull("constraint");
|
|
}
|
|
if (constraint.Table != table) {
|
|
throw ExceptionBuilder.ConstraintRemoveFailed();
|
|
}
|
|
|
|
UnregisterName(constraint.ConstraintName);
|
|
constraint.InCollection = false;
|
|
|
|
if (constraint is UniqueConstraint) {
|
|
for (int i = 0; i < Table.ChildRelations.Count; i++) {
|
|
DataRelation rel = Table.ChildRelations[i];
|
|
if (rel.ParentKeyConstraint == constraint)
|
|
rel.SetParentKeyConstraint(null);
|
|
}
|
|
((UniqueConstraint)constraint).ConstraintIndexClear();
|
|
}
|
|
else if (constraint is ForeignKeyConstraint) {
|
|
for (int i = 0; i < Table.ParentRelations.Count; i++) {
|
|
DataRelation rel = Table.ParentRelations[i];
|
|
if (rel.ChildKeyConstraint == constraint)
|
|
rel.SetChildKeyConstraint(null);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Indicates if a <see cref='System.Data.Constraint'/> can be removed.</para>
|
|
/// </devdoc>
|
|
// PUBLIC because called by design-time... need to consider this.
|
|
public bool CanRemove(Constraint constraint) {
|
|
return CanRemove(constraint, /*fThrowException:*/false);
|
|
}
|
|
|
|
internal bool CanRemove(Constraint constraint, bool fThrowException) {
|
|
return constraint.CanBeRemovedFromCollection(this, fThrowException);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Clears the collection of any <see cref='System.Data.Constraint'/>
|
|
/// objects.</para>
|
|
/// </devdoc>
|
|
public void Clear() {
|
|
if (table != null) {
|
|
table.PrimaryKey = null;
|
|
|
|
for (int i = 0; i < table.ParentRelations.Count; i++) {
|
|
table.ParentRelations[i].SetChildKeyConstraint(null);
|
|
}
|
|
for (int i = 0; i < table.ChildRelations.Count; i++) {
|
|
table.ChildRelations[i].SetParentKeyConstraint(null);
|
|
}
|
|
}
|
|
|
|
if (table.fInitInProgress && delayLoadingConstraints != null) {
|
|
delayLoadingConstraints = null;
|
|
fLoadForeignKeyConstraintsOnly = false;
|
|
}
|
|
|
|
int oldLength = List.Count;
|
|
|
|
Constraint[] constraints = new Constraint[List.Count];
|
|
List.CopyTo(constraints, 0);
|
|
try {
|
|
// this will smartly add and remove the appropriate tables.
|
|
BaseGroupSwitch(constraints, oldLength, null, 0);
|
|
}
|
|
catch (Exception e) {
|
|
//
|
|
if (Common.ADP.IsCatchableOrSecurityExceptionType(e)) {
|
|
// something messed up. restore to original state.
|
|
BaseGroupSwitch(null, 0, constraints, oldLength);
|
|
List.Clear();
|
|
for (int i = 0; i < oldLength; i++)
|
|
List.Add(constraints[i]);
|
|
}
|
|
throw;
|
|
}
|
|
|
|
List.Clear();
|
|
OnCollectionChanged(RefreshEventArgs);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Indicates whether the <see cref='System.Data.Constraint'/>, specified by name, exists in the collection.</para>
|
|
/// </devdoc>
|
|
public bool Contains(string name) {
|
|
return (InternalIndexOf(name) >= 0);
|
|
}
|
|
|
|
internal bool Contains(string name, bool caseSensitive) {
|
|
if (!caseSensitive)
|
|
return Contains(name);
|
|
int index = InternalIndexOf(name);
|
|
if (index<0)
|
|
return false;
|
|
return (name == ((Constraint) List[index]).ConstraintName);
|
|
}
|
|
|
|
public void CopyTo(Constraint[] array, int index) {
|
|
if (array==null)
|
|
throw ExceptionBuilder.ArgumentNull("array");
|
|
if (index < 0)
|
|
throw ExceptionBuilder.ArgumentOutOfRange("index");
|
|
if (array.Length - index < list.Count)
|
|
throw ExceptionBuilder.InvalidOffsetLength();
|
|
for(int i = 0; i < list.Count; ++i) {
|
|
array[index + i] = (Constraint)list[i];
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Returns a matching constriant object.
|
|
/// </devdoc>
|
|
internal Constraint FindConstraint(Constraint constraint) {
|
|
int constraintCount = List.Count;
|
|
for (int i = 0; i < constraintCount; i++) {
|
|
if (((Constraint)List[i]).Equals(constraint))
|
|
return(Constraint)List[i];
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Returns a matching constriant object.
|
|
/// </devdoc>
|
|
internal UniqueConstraint FindKeyConstraint(DataColumn[] columns) {
|
|
int constraintCount = List.Count;
|
|
for (int i = 0; i < constraintCount; i++) {
|
|
UniqueConstraint constraint = (List[i] as UniqueConstraint);
|
|
if ((null != constraint) && CompareArrays(constraint.Key.ColumnsReference, columns)) {
|
|
return constraint;
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Returns a matching constriant object.
|
|
/// </devdoc>
|
|
internal UniqueConstraint FindKeyConstraint(DataColumn column) {
|
|
int constraintCount = List.Count;
|
|
for (int i = 0; i < constraintCount; i++) {
|
|
UniqueConstraint constraint = (List[i] as UniqueConstraint);
|
|
if ((null != constraint) && (constraint.Key.ColumnsReference.Length == 1) && (constraint.Key.ColumnsReference[0] == column))
|
|
return constraint;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Returns a matching constriant object.
|
|
/// </devdoc>
|
|
internal ForeignKeyConstraint FindForeignKeyConstraint(DataColumn[] parentColumns, DataColumn[] childColumns) {
|
|
int constraintCount = List.Count;
|
|
for (int i = 0; i < constraintCount; i++) {
|
|
ForeignKeyConstraint constraint = (List[i] as ForeignKeyConstraint);
|
|
if ((null != constraint) &&
|
|
CompareArrays(constraint.ParentKey.ColumnsReference, parentColumns) &&
|
|
CompareArrays(constraint.ChildKey.ColumnsReference, childColumns))
|
|
return constraint;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
private static bool CompareArrays(DataColumn[] a1, DataColumn[] a2) {
|
|
Debug.Assert(a1 != null && a2 != null, "Invalid Arguments");
|
|
if (a1.Length != a2.Length)
|
|
return false;
|
|
|
|
int i, j;
|
|
for (i=0; i<a1.Length; i++) {
|
|
bool check = false;
|
|
for (j=0; j<a2.Length; j++) {
|
|
if (a1[i] ==a2[j]) {
|
|
check = true;
|
|
break;
|
|
}
|
|
}
|
|
if (!check) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Returns the index of the specified <see cref='System.Data.Constraint'/> .</para>
|
|
/// </devdoc>
|
|
public int IndexOf(Constraint constraint) {
|
|
if (null != constraint) {
|
|
int count = Count;
|
|
for (int i = 0; i < count; ++i) {
|
|
if (constraint == (Constraint) List[i])
|
|
return i;
|
|
}
|
|
// didnt find the constraint
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Returns the index of the <see cref='System.Data.Constraint'/>, specified by name.</para>
|
|
/// </devdoc>
|
|
public int IndexOf(string constraintName) {
|
|
int index = InternalIndexOf(constraintName);
|
|
return (index < 0) ? -1 : index;
|
|
}
|
|
|
|
// Return value:
|
|
// >= 0: find the match
|
|
// -1: No match
|
|
// -2: At least two matches with different cases
|
|
internal int InternalIndexOf(string constraintName) {
|
|
int cachedI = -1;
|
|
if ((null != constraintName) && (0 < constraintName.Length)) {
|
|
int constraintCount = List.Count;
|
|
int result = 0;
|
|
for (int i = 0; i < constraintCount; i++) {
|
|
Constraint constraint = (Constraint) List[i];
|
|
result = NamesEqual(constraint.ConstraintName, constraintName, false, table.Locale);
|
|
if (result == 1)
|
|
return i;
|
|
|
|
if (result == -1)
|
|
cachedI = (cachedI == -1) ? i : -2;
|
|
}
|
|
}
|
|
return cachedI;
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Makes a default name with the given index. e.g. Constraint1, Constraint2, ... Constrainti
|
|
/// </devdoc>
|
|
private string MakeName(int index) {
|
|
if (1 == index) {
|
|
return "Constraint1";
|
|
}
|
|
return "Constraint" + index.ToString(System.Globalization.CultureInfo.InvariantCulture);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Raises the <see cref='System.Data.ConstraintCollection.CollectionChanged'/> event.</para>
|
|
/// </devdoc>
|
|
private void OnCollectionChanged(CollectionChangeEventArgs ccevent) {
|
|
if (onCollectionChanged != null) {
|
|
onCollectionChanged(this, ccevent);
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Registers this name as being used in the collection. Will throw an ArgumentException
|
|
/// if the name is already being used. Called by Add, All property, and Constraint.ConstraintName property.
|
|
/// if the name is equivalent to the next default name to hand out, we increment our defaultNameIndex.
|
|
/// </devdoc>
|
|
internal void RegisterName(string name) {
|
|
Debug.Assert (name != null);
|
|
|
|
int constraintCount = List.Count;
|
|
for (int i = 0; i < constraintCount; i++) {
|
|
if (NamesEqual(name, ((Constraint)List[i]).ConstraintName, true, table.Locale) != 0) {
|
|
throw ExceptionBuilder.DuplicateConstraintName(((Constraint)List[i]).ConstraintName);
|
|
}
|
|
}
|
|
if (NamesEqual(name, MakeName(defaultNameIndex), true, table.Locale) != 0) {
|
|
defaultNameIndex++;
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>
|
|
/// Removes the specified <see cref='System.Data.Constraint'/>
|
|
/// from the collection.</para>
|
|
/// </devdoc>
|
|
public void Remove(Constraint constraint) {
|
|
if (constraint == null)
|
|
throw ExceptionBuilder.ArgumentNull("constraint");
|
|
|
|
// this will throw an exception if it can't be removed, otherwise indicates
|
|
// whether we need to remove it from the collection.
|
|
if (CanRemove(constraint, true)) {
|
|
// constraint can be removed
|
|
BaseRemove(constraint);
|
|
ArrayRemove(constraint);
|
|
if (constraint is UniqueConstraint && ((UniqueConstraint)constraint).IsPrimaryKey) {
|
|
Table.PrimaryKey = null;
|
|
}
|
|
|
|
OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Remove, constraint));
|
|
}
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Removes the constraint at the specified index from the
|
|
/// collection.</para>
|
|
/// </devdoc>
|
|
public void RemoveAt(int index) {
|
|
Constraint c = this[index];
|
|
if (c == null)
|
|
throw ExceptionBuilder.ConstraintOutOfRange(index);
|
|
Remove(c);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// <para>Removes the constraint, specified by name, from the collection.</para>
|
|
/// </devdoc>
|
|
public void Remove(string name) {
|
|
Constraint c = this[name];
|
|
if (c == null)
|
|
throw ExceptionBuilder.ConstraintNotInTheTable(name);
|
|
Remove(c);
|
|
}
|
|
|
|
/// <devdoc>
|
|
/// Unregisters this name as no longer being used in the collection. Called by Remove, All property, and
|
|
/// Constraint.ConstraintName property. If the name is equivalent to the last proposed default name, we walk backwards
|
|
/// to find the next proper default name to use.
|
|
/// </devdoc>
|
|
internal void UnregisterName(string name) {
|
|
if (NamesEqual(name, MakeName(defaultNameIndex - 1), true, table.Locale) != 0) {
|
|
do {
|
|
defaultNameIndex--;
|
|
} while (defaultNameIndex > 1 &&
|
|
!Contains(MakeName(defaultNameIndex - 1)));
|
|
}
|
|
}
|
|
|
|
internal void FinishInitConstraints() {
|
|
if (delayLoadingConstraints == null)
|
|
return;
|
|
|
|
int colCount;
|
|
DataColumn[] parents, childs;
|
|
for (int i = 0; i < delayLoadingConstraints.Length; i++) {
|
|
if (delayLoadingConstraints[i] is UniqueConstraint) {
|
|
if (fLoadForeignKeyConstraintsOnly)
|
|
continue;
|
|
|
|
UniqueConstraint constr = (UniqueConstraint) delayLoadingConstraints[i];
|
|
if (constr.columnNames == null) {
|
|
this.Add(constr);
|
|
continue;
|
|
}
|
|
colCount = constr.columnNames.Length;
|
|
parents = new DataColumn[colCount];
|
|
for (int j = 0; j < colCount; j++)
|
|
parents[j] = table.Columns[constr.columnNames[j]];
|
|
if (constr.bPrimaryKey) {
|
|
if (table.primaryKey != null) {
|
|
throw ExceptionBuilder.AddPrimaryKeyConstraint();
|
|
}
|
|
else {
|
|
Add(constr.ConstraintName,parents,true);
|
|
}
|
|
continue;
|
|
}
|
|
UniqueConstraint newConstraint = new UniqueConstraint(constr.constraintName, parents);
|
|
if (FindConstraint(newConstraint) == null)
|
|
this.Add(newConstraint);
|
|
}
|
|
else {
|
|
ForeignKeyConstraint constr = (ForeignKeyConstraint) delayLoadingConstraints[i];
|
|
if (constr.parentColumnNames == null ||constr.childColumnNames == null) {
|
|
this.Add(constr);
|
|
continue;
|
|
}
|
|
|
|
if (table.DataSet == null) {
|
|
fLoadForeignKeyConstraintsOnly = true;
|
|
continue;
|
|
}
|
|
|
|
colCount = constr.parentColumnNames.Length;
|
|
parents = new DataColumn[colCount];
|
|
childs = new DataColumn[colCount];
|
|
for (int j = 0; j < colCount; j++) {
|
|
if (constr.parentTableNamespace == null)
|
|
parents[j] = table.DataSet.Tables[constr.parentTableName].Columns[constr.parentColumnNames[j]];
|
|
else
|
|
parents[j] = table.DataSet.Tables[constr.parentTableName, constr.parentTableNamespace].Columns[constr.parentColumnNames[j]];
|
|
childs[j] = table.Columns[constr.childColumnNames[j]];
|
|
}
|
|
ForeignKeyConstraint newConstraint = new ForeignKeyConstraint(constr.constraintName, parents, childs);
|
|
newConstraint.AcceptRejectRule = constr.acceptRejectRule;
|
|
newConstraint.DeleteRule = constr.deleteRule;
|
|
newConstraint.UpdateRule = constr.updateRule;
|
|
this.Add(newConstraint);
|
|
}
|
|
}
|
|
|
|
if (!fLoadForeignKeyConstraintsOnly)
|
|
delayLoadingConstraints = null;
|
|
}
|
|
}
|
|
}
|