File: System\Data\DataKey.cs
Web Access
Project: src\src\libraries\System.Data.Common\src\System.Data.Common.csproj (System.Data.Common)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics;
 
namespace System.Data
{
    internal readonly struct DataKey : IEquatable<DataKey>
    {
        private const int maxColumns = 32;
 
        private readonly DataColumn[] _columns;
 
        internal DataKey(DataColumn[] columns, bool copyColumns)
        {
            if (columns == null)
            {
                throw ExceptionBuilder.ArgumentNull(nameof(columns));
            }
 
            if (columns.Length == 0)
            {
                throw ExceptionBuilder.KeyNoColumns();
            }
 
            if (columns.Length > maxColumns)
            {
                throw ExceptionBuilder.KeyTooManyColumns(maxColumns);
            }
 
            for (int i = 0; i < columns.Length; i++)
            {
                if (columns[i] == null)
                {
                    throw ExceptionBuilder.ArgumentNull("column");
                }
            }
 
            for (int i = 0; i < columns.Length; i++)
            {
                for (int j = 0; j < i; j++)
                {
                    if (columns[i] == columns[j])
                    {
                        throw ExceptionBuilder.KeyDuplicateColumns(columns[i].ColumnName);
                    }
                }
            }
 
            if (copyColumns)
            {
                // Need to make a copy of all columns
                _columns = new DataColumn[columns.Length];
                for (int i = 0; i < columns.Length; i++)
                {
                    _columns[i] = columns[i];
                }
            }
            else
            {
                // take ownership of the array passed in
                _columns = columns;
            }
            CheckState();
        }
 
        internal DataColumn[] ColumnsReference => _columns;
        internal bool HasValue => null != _columns;
        internal DataTable Table => _columns[0].Table!;
        internal void CheckState()
        {
            DataTable? table = _columns[0].Table;
 
            if (table == null)
            {
                throw ExceptionBuilder.ColumnNotInAnyTable();
            }
 
            for (int i = 1; i < _columns.Length; i++)
            {
                if (_columns[i].Table == null)
                {
                    throw ExceptionBuilder.ColumnNotInAnyTable();
                }
                if (_columns[i].Table != table)
                {
                    throw ExceptionBuilder.KeyTableMismatch();
                }
            }
        }
 
        //check to see if this.columns && key2's columns are equal regardless of order
        internal bool ColumnsEqual(DataKey key) => ColumnsEqual(_columns, key._columns);
 
        //check to see if columns1 && columns2 are equal regardless of order
        internal static bool ColumnsEqual(DataColumn[] column1, DataColumn[] column2)
        {
            if (column1 == column2)
            {
                return true;
            }
            else if (column1 == null || column2 == null)
            {
                return false;
            }
            else if (column1.Length != column2.Length)
            {
                return false;
            }
            else
            {
                int i, j;
                for (i = 0; i < column1.Length; i++)
                {
                    bool check = false;
                    for (j = 0; j < column2.Length; j++)
                    {
                        if (column1[i].Equals(column2[j]))
                        {
                            check = true;
                            break;
                        }
                    }
                    if (!check)
                    {
                        return false;
                    }
                }
            }
            return true;
        }
 
        internal bool ContainsColumn(DataColumn column)
        {
            for (int i = 0; i < _columns.Length; i++)
            {
                if (column == _columns[i])
                {
                    return true;
                }
            }
            return false;
        }
 
        public override int GetHashCode()
        {
            Debug.Fail("don't put DataKey into a Hashtable");
            return base.GetHashCode();
        }
 
        public override bool Equals(object? value)
        {
            Debug.Fail("need to directly call Equals(DataKey)");
            return Equals((DataKey)value);
        }
 
        public bool Equals(DataKey value)
        {
            //check to see if this.columns && key2's columns are equal...
            DataColumn[] column1 = _columns;
            DataColumn[] column2 = value._columns;
 
            if (column1 == column2)
            {
                return true;
            }
            else if (column1 == null || column2 == null)
            {
                return false;
            }
            else
            {
                return column1.AsSpan().SequenceEqual(column2);
            }
        }
 
        internal string[] GetColumnNames()
        {
            string[] values = new string[_columns.Length];
            for (int i = 0; i < _columns.Length; ++i)
            {
                values[i] = _columns[i].ColumnName;
            }
            return values;
        }
 
        internal IndexField[] GetIndexDesc()
        {
            IndexField[] indexDesc = new IndexField[_columns.Length];
            for (int i = 0; i < _columns.Length; i++)
            {
                indexDesc[i] = new IndexField(_columns[i], false);
            }
            return indexDesc;
        }
 
        internal object[] GetKeyValues(int record)
        {
            object[] values = new object[_columns.Length];
            for (int i = 0; i < _columns.Length; i++)
            {
                values[i] = _columns[i][record];
            }
            return values;
        }
 
        internal Index GetSortIndex() => GetSortIndex(DataViewRowState.CurrentRows);
 
        internal Index GetSortIndex(DataViewRowState recordStates)
        {
            IndexField[] indexDesc = GetIndexDesc();
            return _columns[0].Table!.GetIndex(indexDesc, recordStates, null);
        }
 
        internal bool RecordsEqual(int record1, int record2)
        {
            for (int i = 0; i < _columns.Length; i++)
            {
                if (_columns[i].Compare(record1, record2) != 0)
                {
                    return false;
                }
            }
            return true;
        }
 
        internal DataColumn[] ToArray()
        {
            DataColumn[] values = new DataColumn[_columns.Length];
            for (int i = 0; i < _columns.Length; ++i)
            {
                values[i] = _columns[i];
            }
            return values;
        }
    }
}