You've already forked linux-packaging-mono
Imported Upstream version 4.6.0.125
Former-commit-id: a2155e9bd80020e49e72e86c44da02a8ac0e57a4
This commit is contained in:
parent
a569aebcfd
commit
e79aa3c0ed
@@ -0,0 +1,26 @@
|
||||
//---------------------------------------------------------------------
|
||||
// <copyright file="GlobalSuppressions.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <summary>global code analysis suppressions</summary>
|
||||
//---------------------------------------------------------------------
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
// They recommend something along the lines of 'TypedBaseDataTable' instead of 'TypedTableBase', this can't be changed at this point
|
||||
[module: SuppressMessage("Microsoft.Naming","CA1710:IdentifiersShouldHaveCorrectSuffix", Scope="type", Target="System.Data.TypedTableBase`1")]
|
||||
|
||||
// Select<TRow, S>(...) should have something more meaningfull than just 'S'
|
||||
[module: SuppressMessage("Microsoft.Naming","CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId="S", Scope="member", Target="System.Data.EnumerableRowCollectionExtensions.#Select`2(System.Data.EnumerableRowCollection`1<!!0>,System.Func`2<!!0,!!1>)")]
|
||||
[module: SuppressMessage("Microsoft.Naming","CA1715:IdentifiersShouldHaveCorrectPrefix", MessageId="T", Scope="member", Target="System.Data.EnumerableRowCollectionExtensions.#Select`2(System.Data.EnumerableRowCollection`1<!!0>,System.Func`2<!!0,!!1>)")]
|
||||
[module: SuppressMessage("Microsoft.Naming","CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId="S", Scope="member", Target="System.Data.TypedTableBaseExtensions.#Select`2(System.Data.TypedTableBase`1<!!0>,System.Func`2<!!0,!!1>)")]
|
||||
[module: SuppressMessage("Microsoft.Naming","CA1715:IdentifiersShouldHaveCorrectPrefix", MessageId="T", Scope="member", Target="System.Data.TypedTableBaseExtensions.#Select`2(System.Data.TypedTableBase`1<!!0>,System.Func`2<!!0,!!1>)")]
|
||||
|
||||
// Violations in the generated Resource file; can't prevent these from being generated...
|
||||
[module: SuppressMessage("Microsoft.Performance","CA1811:AvoidUncalledPrivateCode", Scope="member", Target="System.Data.DataSetRes.#GetObject(System.String)")]
|
||||
[module: SuppressMessage("Microsoft.Performance","CA1811:AvoidUncalledPrivateCode", Scope="member", Target="System.Data.DataSetRes.#GetString(System.String,System.Boolean&)")]
|
||||
[module: SuppressMessage("Microsoft.Performance","CA1811:AvoidUncalledPrivateCode", Scope="member", Target="System.Data.DataSetRes.#get_Resources()")]
|
||||
[module: SuppressMessage("Microsoft.Performance","CA1811:AvoidUncalledPrivateCode", Scope="member", Target="System.Data.DataSetExtensions.Error.#ArgumentNull(System.String)")]
|
||||
[module: SuppressMessage("Microsoft.Performance","CA1811:AvoidUncalledPrivateCode", Scope="member", Target="System.Data.DataSetExtensions.Error.#ArgumentOutOfRange(System.String)")]
|
||||
[module: SuppressMessage("Microsoft.Performance","CA1811:AvoidUncalledPrivateCode", Scope="member", Target="System.Data.DataSetExtensions.Error.#NotImplemented()", Justification="")]
|
||||
[module: SuppressMessage("Microsoft.Performance","CA1811:AvoidUncalledPrivateCode", Scope="member", Target="System.Data.DataSetExtensions.Error.#NotSupported()")]
|
||||
@@ -0,0 +1,21 @@
|
||||
; These are the managed resources for System.Data.DataSetExtensions.dll. See
|
||||
; ResourceManager documentation and the ResGen tool, which is
|
||||
; a managed app built from \com99\src\toolbox\resgen.
|
||||
|
||||
|
||||
DataSetLinq_InvalidEnumerationValue=The {0} enumeration value, {1}, is not valid.
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; System.Data.DataSetLinq error messages
|
||||
DataSetLinq_EmptyDataRowSource=The source contains no DataRows.
|
||||
DataSetLinq_NullDataRow=The source contains a DataRow reference that is null.
|
||||
DataSetLinq_CannotLoadDeletedRow=The source contains a deleted DataRow that cannot be copied to the DataTable.
|
||||
DataSetLinq_CannotLoadDetachedRow=The source contains a detached DataRow that cannot be copied to the DataTable.
|
||||
DataSetLinq_CannotCompareDeletedRow=The DataRowComparer does not work with DataRows that have been deleted since it only compares current values.
|
||||
DataSetLinq_NonNullableCast=Cannot cast DBNull.Value to type '{0}'. Please use a nullable type.
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; System.Data.LinqDataView Error Messages
|
||||
ToLDVUnsupported=Can not create DataView after using projection
|
||||
LDV_InvalidNumOfKeys=Must provide '{0}' keys to find
|
||||
LDVRowStateError=DataViewRowState must be DataViewRowState.CurrentRows
|
||||
@@ -0,0 +1,246 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DataRowComparer.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">spather</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Data.DataSetExtensions;
|
||||
|
||||
namespace System.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// This class implements IEqualityComparer using value based semantics
|
||||
/// when comparing DataRows.
|
||||
/// </summary>
|
||||
public static class DataRowComparer
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the singleton instance of the data row comparer.
|
||||
/// </summary>
|
||||
public static DataRowComparer<DataRow> Default { get { return DataRowComparer<DataRow>.Default; } }
|
||||
|
||||
internal static bool AreEqual(object a, object b)
|
||||
{
|
||||
if (Object.ReferenceEquals(a, b))
|
||||
{ // same reference or (null, null) or (DBNull.Value, DBNull.Value)
|
||||
return true;
|
||||
}
|
||||
if (Object.ReferenceEquals(a, null) || Object.ReferenceEquals(a, DBNull.Value) ||
|
||||
Object.ReferenceEquals(b, null) || Object.ReferenceEquals(b, DBNull.Value))
|
||||
{ // (null, non-null) or (null, DBNull.Value) or vice versa
|
||||
return false;
|
||||
}
|
||||
return (a.Equals(b) || (a.GetType().IsArray && CompareArray((Array)a, b as Array)));
|
||||
}
|
||||
|
||||
private static bool AreElementEqual(object a, object b)
|
||||
{
|
||||
if (Object.ReferenceEquals(a, b))
|
||||
{ // same reference or (null, null) or (DBNull.Value, DBNull.Value)
|
||||
return true;
|
||||
}
|
||||
if (Object.ReferenceEquals(a, null) || Object.ReferenceEquals(a, DBNull.Value) ||
|
||||
Object.ReferenceEquals(b, null) || Object.ReferenceEquals(b, DBNull.Value))
|
||||
{ // (null, non-null) or (null, DBNull.Value) or vice versa
|
||||
return false;
|
||||
}
|
||||
return a.Equals(b);
|
||||
}
|
||||
|
||||
private static bool CompareArray(Array a, Array b)
|
||||
{
|
||||
if ((null == b) ||
|
||||
(1 != a.Rank) ||
|
||||
(1 != b.Rank) ||
|
||||
(a.Length != b.Length))
|
||||
{ // automatically consider array's with Rank>1 not-equal
|
||||
return false;
|
||||
}
|
||||
|
||||
int index1 = a.GetLowerBound(0);
|
||||
int index2 = b.GetLowerBound(0);
|
||||
if (a.GetType() == b.GetType() && (0 == index1) && (0 == index2))
|
||||
{
|
||||
switch (Type.GetTypeCode(a.GetType().GetElementType()))
|
||||
{
|
||||
case TypeCode.Byte:
|
||||
return DataRowComparer.CompareEquatableArray<Byte>((Byte[])a, (Byte[])b);
|
||||
case TypeCode.Int16:
|
||||
return DataRowComparer.CompareEquatableArray<Int16>((Int16[])a, (Int16[])b);
|
||||
case TypeCode.Int32:
|
||||
return DataRowComparer.CompareEquatableArray<Int32>((Int32[])a, (Int32[])b);
|
||||
case TypeCode.Int64:
|
||||
return DataRowComparer.CompareEquatableArray<Int64>((Int64[])a, (Int64[])b);
|
||||
case TypeCode.String:
|
||||
return DataRowComparer.CompareEquatableArray<String>((String[])a, (String[])b);
|
||||
}
|
||||
}
|
||||
|
||||
//Compare every element. But don't recurse if we have Array of array.
|
||||
int length = index1 + a.Length;
|
||||
for (; index1 < length; ++index1, ++index2)
|
||||
{
|
||||
if (!AreElementEqual(a.GetValue(index1), b.GetValue(index2)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool CompareEquatableArray<TElem>(TElem[] a, TElem[] b) where TElem : IEquatable<TElem>
|
||||
{
|
||||
if (Object.ReferenceEquals(a, b))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (Object.ReferenceEquals(a, null) ||
|
||||
Object.ReferenceEquals(b, null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (a.Length != b.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < a.Length; ++i)
|
||||
{
|
||||
if (!a[i].Equals(b[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class implements IEqualityComparer using value based semantics
|
||||
/// when comparing DataRows.
|
||||
/// </summary>
|
||||
public sealed class DataRowComparer<TRow> : IEqualityComparer<TRow> where TRow : DataRow
|
||||
{
|
||||
/// <summary>
|
||||
/// Private constructor to prevent initialization outside of Default singleton instance.
|
||||
/// </summary>
|
||||
private DataRowComparer() { }
|
||||
|
||||
private static DataRowComparer<TRow> _instance = new DataRowComparer<TRow>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the singleton instance of the data row comparer.
|
||||
/// </summary>
|
||||
public static DataRowComparer<TRow> Default { get { return _instance; } }
|
||||
|
||||
/// <summary>
|
||||
/// This method compares to DataRows by doing a column by column value based
|
||||
/// comparision.
|
||||
/// </summary>
|
||||
/// <param name="leftRow">
|
||||
/// The first input DataRow
|
||||
/// </param>
|
||||
/// <param name="rightRow">
|
||||
/// The second input DataRow
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// True if rows are equal, false if not.
|
||||
/// </returns>
|
||||
public bool Equals(TRow leftRow, TRow rightRow)
|
||||
{
|
||||
if (Object.ReferenceEquals(leftRow, rightRow))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (Object.ReferenceEquals(leftRow, null) ||
|
||||
Object.ReferenceEquals(rightRow, null))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (leftRow.RowState == DataRowState.Deleted || rightRow.RowState == DataRowState.Deleted)
|
||||
{
|
||||
throw DataSetUtil.InvalidOperation(Strings.DataSetLinq_CannotCompareDeletedRow);
|
||||
}
|
||||
|
||||
int count = leftRow.Table.Columns.Count;
|
||||
if (count != rightRow.Table.Columns.Count)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
if (!DataRowComparer.AreEqual(leftRow[i], rightRow[i]))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This mtheod retrieves a hash code for the source row.
|
||||
/// </summary>
|
||||
/// <param name="row">
|
||||
/// The source DataRow
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// HashCode for row based on values in the row.
|
||||
/// </returns>
|
||||
public int GetHashCode(TRow row)
|
||||
{
|
||||
DataSetUtil.CheckArgumentNull(row, "row");
|
||||
|
||||
if (row.RowState == DataRowState.Deleted)
|
||||
{
|
||||
throw DataSetUtil.InvalidOperation(Strings.DataSetLinq_CannotCompareDeletedRow);
|
||||
}
|
||||
|
||||
int hash = 0;
|
||||
Debug.Assert(row.Table != null);
|
||||
if (row.Table.Columns.Count > 0)
|
||||
{
|
||||
// if the row has at least one column, then use the first column value
|
||||
object value = row[0];
|
||||
|
||||
Type valueType = value.GetType();
|
||||
if (valueType.IsArray)
|
||||
{
|
||||
Array array = value as Array;
|
||||
|
||||
if (array.Rank > 1)
|
||||
{
|
||||
hash = value.GetHashCode();
|
||||
}
|
||||
else if (array.Length > 0)
|
||||
{
|
||||
hash = array.GetValue(array.GetLowerBound(0)).GetHashCode();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
System.ValueType vt = value as System.ValueType;
|
||||
|
||||
// have to unbox value types.
|
||||
if (vt != null)
|
||||
{
|
||||
hash = vt.GetHashCode();
|
||||
}
|
||||
else
|
||||
{
|
||||
hash = value.GetHashCode();
|
||||
}
|
||||
}
|
||||
}
|
||||
// if table has no columns, the hash code is 0
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DataRowExtenstions.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">spather</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Data.DataSetExtensions;
|
||||
|
||||
namespace System.Data {
|
||||
|
||||
/// <summary>
|
||||
/// This static class defines the DataRow extension methods.
|
||||
/// </summary>
|
||||
public static class DataRowExtensions {
|
||||
|
||||
/// <summary>
|
||||
/// This method provides access to the values in each of the columns in a given row.
|
||||
/// This method makes casts unnecessary when accessing columns.
|
||||
/// Additionally, Field supports nullable types and maps automatically between DBNull and
|
||||
/// Nullable when the generic type is nullable.
|
||||
/// </summary>
|
||||
/// <param name="row">
|
||||
/// The input DataRow
|
||||
/// </param>
|
||||
/// <param name="columnName">
|
||||
/// The input column name specificy which row value to retrieve.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The DataRow value for the column specified.
|
||||
/// </returns>
|
||||
public static T Field<T>(this DataRow row, string columnName) {
|
||||
DataSetUtil.CheckArgumentNull(row, "row");
|
||||
return UnboxT<T>.Unbox(row[columnName]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method provides access to the values in each of the columns in a given row.
|
||||
/// This method makes casts unnecessary when accessing columns.
|
||||
/// Additionally, Field supports nullable types and maps automatically between DBNull and
|
||||
/// Nullable when the generic type is nullable.
|
||||
/// </summary>
|
||||
/// <param name="row">
|
||||
/// The input DataRow
|
||||
/// </param>
|
||||
/// <param name="column">
|
||||
/// The input DataColumn specificy which row value to retrieve.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The DataRow value for the column specified.
|
||||
/// </returns>
|
||||
public static T Field<T>(this DataRow row, DataColumn column) {
|
||||
DataSetUtil.CheckArgumentNull(row, "row");
|
||||
return UnboxT<T>.Unbox(row[column]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method provides access to the values in each of the columns in a given row.
|
||||
/// This method makes casts unnecessary when accessing columns.
|
||||
/// Additionally, Field supports nullable types and maps automatically between DBNull and
|
||||
/// Nullable when the generic type is nullable.
|
||||
/// </summary>
|
||||
/// <param name="row">
|
||||
/// The input DataRow
|
||||
/// </param>
|
||||
/// <param name="columnIndex">
|
||||
/// The input ordinal specificy which row value to retrieve.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The DataRow value for the column specified.
|
||||
/// </returns>
|
||||
public static T Field<T>(this DataRow row, int columnIndex) {
|
||||
DataSetUtil.CheckArgumentNull(row, "row");
|
||||
return UnboxT<T>.Unbox(row[columnIndex]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method provides access to the values in each of the columns in a given row.
|
||||
/// This method makes casts unnecessary when accessing columns.
|
||||
/// Additionally, Field supports nullable types and maps automatically between DBNull and
|
||||
/// Nullable when the generic type is nullable.
|
||||
/// </summary>
|
||||
/// <param name="row">
|
||||
/// The input DataRow
|
||||
/// </param>
|
||||
/// <param name="columnIndex">
|
||||
/// The input ordinal specificy which row value to retrieve.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// The DataRow version for which row value to retrieve.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The DataRow value for the column specified.
|
||||
/// </returns>
|
||||
public static T Field<T>(this DataRow row, int columnIndex, DataRowVersion version) {
|
||||
DataSetUtil.CheckArgumentNull(row, "row");
|
||||
return UnboxT<T>.Unbox(row[columnIndex, version]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method provides access to the values in each of the columns in a given row.
|
||||
/// This method makes casts unnecessary when accessing columns.
|
||||
/// Additionally, Field supports nullable types and maps automatically between DBNull and
|
||||
/// Nullable when the generic type is nullable.
|
||||
/// </summary>
|
||||
/// <param name="row">
|
||||
/// The input DataRow
|
||||
/// </param>
|
||||
/// <param name="columnName">
|
||||
/// The input column name specificy which row value to retrieve.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// The DataRow version for which row value to retrieve.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The DataRow value for the column specified.
|
||||
/// </returns>
|
||||
public static T Field<T>(this DataRow row, string columnName, DataRowVersion version) {
|
||||
DataSetUtil.CheckArgumentNull(row, "row");
|
||||
return UnboxT<T>.Unbox(row[columnName, version]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method provides access to the values in each of the columns in a given row.
|
||||
/// This method makes casts unnecessary when accessing columns.
|
||||
/// Additionally, Field supports nullable types and maps automatically between DBNull and
|
||||
/// Nullable when the generic type is nullable.
|
||||
/// </summary>
|
||||
/// <param name="row">
|
||||
/// The input DataRow
|
||||
/// </param>
|
||||
/// <param name="column">
|
||||
/// The input DataColumn specificy which row value to retrieve.
|
||||
/// </param>
|
||||
/// <param name="version">
|
||||
/// The DataRow version for which row value to retrieve.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The DataRow value for the column specified.
|
||||
/// </returns>
|
||||
public static T Field<T>(this DataRow row, DataColumn column, DataRowVersion version) {
|
||||
DataSetUtil.CheckArgumentNull(row, "row");
|
||||
return UnboxT<T>.Unbox(row[column, version]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method sets a new value for the specified column for the DataRow it<69>s called on.
|
||||
/// </summary>
|
||||
/// <param name="row">
|
||||
/// The input DataRow.
|
||||
/// </param>
|
||||
/// <param name="columnIndex">
|
||||
/// The input ordinal specifying which row value to set.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// The new row value for the specified column.
|
||||
/// </param>
|
||||
public static void SetField<T>(this DataRow row, int columnIndex, T value) {
|
||||
DataSetUtil.CheckArgumentNull(row, "row");
|
||||
row[columnIndex] = (object)value ?? DBNull.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method sets a new value for the specified column for the DataRow it<69>s called on.
|
||||
/// </summary>
|
||||
/// <param name="row">
|
||||
/// The input DataRow.
|
||||
/// </param>
|
||||
/// <param name="columnName">
|
||||
/// The input column name specificy which row value to retrieve.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// The new row value for the specified column.
|
||||
/// </param>
|
||||
public static void SetField<T>(this DataRow row, string columnName, T value) {
|
||||
DataSetUtil.CheckArgumentNull(row, "row");
|
||||
row[columnName] = (object)value ?? DBNull.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method sets a new value for the specified column for the DataRow it<69>s called on.
|
||||
/// </summary>
|
||||
/// <param name="row">
|
||||
/// The input DataRow.
|
||||
/// </param>
|
||||
/// <param name="column">
|
||||
/// The input DataColumn specificy which row value to retrieve.
|
||||
/// </param>
|
||||
/// <param name="value">
|
||||
/// The new row value for the specified column.
|
||||
/// </param>
|
||||
public static void SetField<T>(this DataRow row, DataColumn column, T value) {
|
||||
DataSetUtil.CheckArgumentNull(row, "row");
|
||||
row[column] = (object)value ?? DBNull.Value;
|
||||
}
|
||||
|
||||
private static class UnboxT<T>
|
||||
{
|
||||
internal static readonly Converter<object, T> Unbox = Create(typeof(T));
|
||||
|
||||
private static Converter<object, T> Create(Type type)
|
||||
{
|
||||
if (type.IsValueType)
|
||||
{
|
||||
if (type.IsGenericType && !type.IsGenericTypeDefinition && (typeof(Nullable<>) == type.GetGenericTypeDefinition()))
|
||||
{
|
||||
return (Converter<object, T>)Delegate.CreateDelegate(
|
||||
typeof(Converter<object, T>),
|
||||
typeof(UnboxT<T>)
|
||||
.GetMethod("NullableField", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic)
|
||||
.MakeGenericMethod(type.GetGenericArguments()[0]));
|
||||
}
|
||||
return ValueField;
|
||||
}
|
||||
return ReferenceField;
|
||||
}
|
||||
|
||||
private static T ReferenceField(object value)
|
||||
{
|
||||
return ((DBNull.Value == value) ? default(T) : (T)value);
|
||||
}
|
||||
|
||||
private static T ValueField(object value)
|
||||
{
|
||||
if (DBNull.Value == value)
|
||||
{
|
||||
throw DataSetUtil.InvalidCast(Strings.DataSetLinq_NonNullableCast(typeof(T).ToString()));
|
||||
}
|
||||
return (T)value;
|
||||
}
|
||||
|
||||
private static Nullable<TElem> NullableField<TElem>(object value) where TElem : struct
|
||||
{
|
||||
if (DBNull.Value == value)
|
||||
{
|
||||
return default(Nullable<TElem>);
|
||||
}
|
||||
return new Nullable<TElem>((TElem)value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DataSetUtil.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
using System.Data.DataSetExtensions;
|
||||
using System.Diagnostics;
|
||||
|
||||
internal static class DataSetUtil
|
||||
{
|
||||
#region CheckArgument
|
||||
internal static void CheckArgumentNull<T>(T argumentValue, string argumentName) where T : class
|
||||
{
|
||||
if (null == argumentValue)
|
||||
{
|
||||
throw ArgumentNull(argumentName);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Trace
|
||||
private static T TraceException<T>(string trace, T e)
|
||||
{
|
||||
Debug.Assert(null != e, "TraceException: null Exception");
|
||||
if (null != e)
|
||||
{
|
||||
//Bid.Trace(trace, e.ToString()); // will include callstack if permission is available
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
private static T TraceExceptionAsReturnValue<T>(T e)
|
||||
{
|
||||
return TraceException("<comm.ADP.TraceException|ERR|THROW> '%ls'\n", e);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region new Exception
|
||||
internal static ArgumentException Argument(string message)
|
||||
{
|
||||
return TraceExceptionAsReturnValue(new ArgumentException(message));
|
||||
}
|
||||
|
||||
internal static ArgumentNullException ArgumentNull(string message)
|
||||
{
|
||||
return TraceExceptionAsReturnValue(new ArgumentNullException(message));
|
||||
}
|
||||
|
||||
internal static ArgumentOutOfRangeException ArgumentOutOfRange(string message, string parameterName)
|
||||
{
|
||||
return TraceExceptionAsReturnValue(new ArgumentOutOfRangeException(parameterName, message));
|
||||
}
|
||||
|
||||
internal static InvalidCastException InvalidCast(string message)
|
||||
{
|
||||
return TraceExceptionAsReturnValue(new InvalidCastException(message));
|
||||
}
|
||||
|
||||
internal static InvalidOperationException InvalidOperation(string message)
|
||||
{
|
||||
return TraceExceptionAsReturnValue(new InvalidOperationException(message));
|
||||
}
|
||||
|
||||
internal static NotSupportedException NotSupported(string message)
|
||||
{
|
||||
return TraceExceptionAsReturnValue(new NotSupportedException(message));
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region new EnumerationValueNotValid
|
||||
static internal ArgumentOutOfRangeException InvalidEnumerationValue(Type type, int value)
|
||||
{
|
||||
return ArgumentOutOfRange(Strings.DataSetLinq_InvalidEnumerationValue(type.Name, value.ToString(System.Globalization.CultureInfo.InvariantCulture)), type.Name);
|
||||
}
|
||||
|
||||
static internal ArgumentOutOfRangeException InvalidDataRowState(DataRowState value)
|
||||
{
|
||||
#if DEBUG
|
||||
switch (value)
|
||||
{
|
||||
case DataRowState.Detached:
|
||||
case DataRowState.Unchanged:
|
||||
case DataRowState.Added:
|
||||
case DataRowState.Deleted:
|
||||
case DataRowState.Modified:
|
||||
Debug.Assert(false, "valid DataRowState " + value.ToString());
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return InvalidEnumerationValue(typeof(DataRowState), (int)value);
|
||||
}
|
||||
|
||||
static internal ArgumentOutOfRangeException InvalidLoadOption(LoadOption value)
|
||||
{
|
||||
#if DEBUG
|
||||
switch (value)
|
||||
{
|
||||
case LoadOption.OverwriteChanges:
|
||||
case LoadOption.PreserveChanges:
|
||||
case LoadOption.Upsert:
|
||||
Debug.Assert(false, "valid LoadOption " + value.ToString());
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
return InvalidEnumerationValue(typeof(LoadOption), (int)value);
|
||||
}
|
||||
#endregion
|
||||
|
||||
// only StackOverflowException & ThreadAbortException are sealed classes
|
||||
static private readonly Type StackOverflowType = typeof(System.StackOverflowException);
|
||||
static private readonly Type OutOfMemoryType = typeof(System.OutOfMemoryException);
|
||||
static private readonly Type ThreadAbortType = typeof(System.Threading.ThreadAbortException);
|
||||
static private readonly Type NullReferenceType = typeof(System.NullReferenceException);
|
||||
static private readonly Type AccessViolationType = typeof(System.AccessViolationException);
|
||||
static private readonly Type SecurityType = typeof(System.Security.SecurityException);
|
||||
|
||||
static internal bool IsCatchableExceptionType(Exception e)
|
||||
{
|
||||
// a 'catchable' exception is defined by what it is not.
|
||||
Type type = e.GetType();
|
||||
|
||||
return ((type != StackOverflowType) &&
|
||||
(type != OutOfMemoryType) &&
|
||||
(type != ThreadAbortType) &&
|
||||
(type != NullReferenceType) &&
|
||||
(type != AccessViolationType) &&
|
||||
!SecurityType.IsAssignableFrom(type));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,280 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="DataTableExtenstions.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using System.Linq.Expressions;
|
||||
using System.Globalization;
|
||||
using System.Diagnostics;
|
||||
using System.Data.DataSetExtensions;
|
||||
|
||||
namespace System.Data
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This static class defines the DataTable extension methods.
|
||||
/// </summary>
|
||||
public static class DataTableExtensions
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This method returns a IEnumerable of Datarows.
|
||||
/// </summary>
|
||||
/// <param name="source">
|
||||
/// The source DataTable to make enumerable.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// IEnumerable of datarows.
|
||||
/// </returns>
|
||||
public static EnumerableRowCollection<DataRow> AsEnumerable(this DataTable source)
|
||||
{
|
||||
DataSetUtil.CheckArgumentNull(source, "source");
|
||||
return new EnumerableRowCollection<DataRow>(source);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method takes an input sequence of DataRows and produces a DataTable object
|
||||
/// with copies of the source rows.
|
||||
/// Also note that this will cause the rest of the query to execute at this point in time
|
||||
/// (e.g. there is no more delayed execution after this sequence operator).
|
||||
/// </summary>
|
||||
/// <param name="source">
|
||||
/// The input sequence of DataRows
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// DataTable containing copies of the source DataRows.
|
||||
/// Properties for the DataTable table will be taken from first DataRow in the source.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">if source is null</exception>
|
||||
/// <exception cref="InvalidOperationException">if source is empty</exception>
|
||||
public static DataTable CopyToDataTable<T>(this IEnumerable<T> source)
|
||||
where T : DataRow
|
||||
{
|
||||
DataSetUtil.CheckArgumentNull(source, "source");
|
||||
return LoadTableFromEnumerable(source, null, null, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// delegates to other CopyToDataTable overload with a null FillErrorEventHandler.
|
||||
/// </summary>
|
||||
public static void CopyToDataTable<T>(this IEnumerable<T> source, DataTable table, LoadOption options)
|
||||
where T : DataRow
|
||||
{
|
||||
DataSetUtil.CheckArgumentNull(source, "source");
|
||||
DataSetUtil.CheckArgumentNull(table, "table");
|
||||
LoadTableFromEnumerable(source, table, options, null);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This method takes an input sequence of DataRows and produces a DataTable object
|
||||
/// with copies of the source rows.
|
||||
/// Also note that this will cause the rest of the query to execute at this point in time
|
||||
/// (e.g. there is no more delayed execution after this sequence operator).
|
||||
/// </summary>
|
||||
/// <param name="source">
|
||||
/// The input sequence of DataRows
|
||||
///
|
||||
/// CopyToDataTable uses DataRowVersion.Default when retrieving values from source DataRow
|
||||
/// which will include proposed values for DataRow being edited.
|
||||
///
|
||||
/// Null DataRow in the sequence are skipped.
|
||||
/// </param>
|
||||
/// <param name="table">
|
||||
/// The target DataTable to load.
|
||||
/// </param>
|
||||
/// <param name="options">
|
||||
/// The target DataTable to load.
|
||||
/// </param>
|
||||
/// <param name="errorHandler">
|
||||
/// Error handler for recoverable errors.
|
||||
/// Recoverable errors include:
|
||||
/// A source DataRow is in the deleted or detached state state.
|
||||
/// DataTable.LoadDataRow threw an exception, i.e. wrong # of columns in source row
|
||||
/// Unrecoverable errors include:
|
||||
/// exceptions from IEnumerator, DataTable.BeginLoadData or DataTable.EndLoadData
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// DataTable containing copies of the source DataRows.
|
||||
/// </returns>
|
||||
/// <exception cref="ArgumentNullException">if source is null</exception>
|
||||
/// <exception cref="ArgumentNullException">if table is null</exception>
|
||||
/// <exception cref="InvalidOperationException">if source DataRow is in Deleted or Detached state</exception>
|
||||
public static void CopyToDataTable<T>(this IEnumerable<T> source, DataTable table, LoadOption options, FillErrorEventHandler errorHandler)
|
||||
where T : DataRow
|
||||
{
|
||||
DataSetUtil.CheckArgumentNull(source, "source");
|
||||
DataSetUtil.CheckArgumentNull(table, "table");
|
||||
LoadTableFromEnumerable(source, table, options, errorHandler);
|
||||
}
|
||||
|
||||
private static DataTable LoadTableFromEnumerable<T>(IEnumerable<T> source, DataTable table, LoadOption? options, FillErrorEventHandler errorHandler)
|
||||
where T : DataRow
|
||||
{
|
||||
if (options.HasValue) {
|
||||
switch(options.Value) {
|
||||
case LoadOption.OverwriteChanges:
|
||||
case LoadOption.PreserveChanges:
|
||||
case LoadOption.Upsert:
|
||||
break;
|
||||
default:
|
||||
throw DataSetUtil.InvalidLoadOption(options.Value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
using (IEnumerator<T> rows = source.GetEnumerator())
|
||||
{
|
||||
// need to get first row to create table
|
||||
if (!rows.MoveNext())
|
||||
{
|
||||
if (table == null)
|
||||
{
|
||||
throw DataSetUtil.InvalidOperation(Strings.DataSetLinq_EmptyDataRowSource);
|
||||
}
|
||||
else
|
||||
{
|
||||
return table;
|
||||
}
|
||||
}
|
||||
|
||||
DataRow current;
|
||||
if (table == null)
|
||||
{
|
||||
current = rows.Current;
|
||||
if (current == null)
|
||||
{
|
||||
throw DataSetUtil.InvalidOperation(Strings.DataSetLinq_NullDataRow);
|
||||
}
|
||||
|
||||
table = new DataTable();
|
||||
table.Locale = CultureInfo.CurrentCulture;
|
||||
// We do not copy the same properties that DataView.ToTable does.
|
||||
// If user needs that functionality, use other CopyToDataTable overloads.
|
||||
// The reasoning being, the IEnumerator<DataRow> can be sourced from
|
||||
// different DataTable, so we just use the "Default" instead of resolving the difference.
|
||||
|
||||
foreach (DataColumn column in current.Table.Columns)
|
||||
{
|
||||
table.Columns.Add(column.ColumnName, column.DataType);
|
||||
}
|
||||
}
|
||||
|
||||
table.BeginLoadData();
|
||||
try
|
||||
{
|
||||
do
|
||||
{
|
||||
current = rows.Current;
|
||||
if (current == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
object[] values = null;
|
||||
try
|
||||
{ // 'recoverable' error block
|
||||
switch(current.RowState)
|
||||
{
|
||||
case DataRowState.Detached:
|
||||
if (!current.HasVersion(DataRowVersion.Proposed))
|
||||
{
|
||||
throw DataSetUtil.InvalidOperation(Strings.DataSetLinq_CannotLoadDetachedRow);
|
||||
}
|
||||
goto case DataRowState.Added;
|
||||
case DataRowState.Unchanged:
|
||||
case DataRowState.Added:
|
||||
case DataRowState.Modified:
|
||||
values = current.ItemArray;
|
||||
if (options.HasValue)
|
||||
{
|
||||
table.LoadDataRow(values, options.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
table.LoadDataRow(values, true);
|
||||
}
|
||||
break;
|
||||
case DataRowState.Deleted:
|
||||
throw DataSetUtil.InvalidOperation(Strings.DataSetLinq_CannotLoadDeletedRow);
|
||||
default:
|
||||
throw DataSetUtil.InvalidDataRowState(current.RowState);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (!DataSetUtil.IsCatchableExceptionType(e))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
FillErrorEventArgs fillError = null;
|
||||
if (null != errorHandler)
|
||||
{
|
||||
fillError = new FillErrorEventArgs(table, values);
|
||||
fillError.Errors = e;
|
||||
errorHandler.Invoke(rows, fillError);
|
||||
}
|
||||
if (null == fillError) {
|
||||
throw;
|
||||
}
|
||||
else if (!fillError.Continue)
|
||||
{
|
||||
if (Object.ReferenceEquals(fillError.Errors ?? e, e))
|
||||
{ // if user didn't change exception to throw (or set it to null)
|
||||
throw;
|
||||
}
|
||||
else
|
||||
{ // user may have changed exception to throw in handler
|
||||
throw fillError.Errors;
|
||||
}
|
||||
}
|
||||
}
|
||||
} while (rows.MoveNext());
|
||||
}
|
||||
finally
|
||||
{
|
||||
table.EndLoadData();
|
||||
}
|
||||
}
|
||||
Debug.Assert(null != table, "null DataTable");
|
||||
return table;
|
||||
}
|
||||
|
||||
#region Methods to Create LinqDataView
|
||||
|
||||
/// <summary>
|
||||
/// Creates a LinkDataView of DataRow over the input table.
|
||||
/// </summary>
|
||||
/// <param name="table">DataTable that the view is over.</param>
|
||||
/// <returns>An instance of LinkDataView.</returns>
|
||||
public static DataView AsDataView(this DataTable table)
|
||||
{
|
||||
DataSetUtil.CheckArgumentNull<DataTable>(table, "table");
|
||||
return new LinqDataView(table, null);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a LinqDataView from EnumerableDataTable
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the row in the table. Must inherit from DataRow</typeparam>
|
||||
/// <param name="source">The enumerable-datatable over which view must be created.</param>
|
||||
/// <returns>Generated LinkDataView of type T</returns>
|
||||
public static DataView AsDataView<T>(this EnumerableRowCollection<T> source) where T : DataRow
|
||||
{
|
||||
DataSetUtil.CheckArgumentNull<EnumerableRowCollection<T>>(source, "source");
|
||||
return source.GetLinqDataView();
|
||||
}
|
||||
|
||||
#endregion LinqDataView
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,356 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="GenericEnumRowCollection.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System.Text;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.Linq.Expressions;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Data.DataSetExtensions;
|
||||
|
||||
namespace System.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides an entry point so that Cast operator call can be intercepted within an extension method.
|
||||
/// </summary>
|
||||
public abstract class EnumerableRowCollection : IEnumerable
|
||||
{
|
||||
internal abstract Type ElementType { get; }
|
||||
internal abstract DataTable Table { get; }
|
||||
|
||||
internal EnumerableRowCollection()
|
||||
{
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This class provides a wrapper for DataTables to allow for querying via LINQ.
|
||||
/// </summary>
|
||||
public class EnumerableRowCollection<TRow> : EnumerableRowCollection, IEnumerable<TRow>
|
||||
{
|
||||
private readonly DataTable _table;
|
||||
private readonly IEnumerable<TRow> _enumerableRows;
|
||||
private readonly List<Func<TRow, bool>> _listOfPredicates;
|
||||
|
||||
// Stores list of sort expression in the order provided by user. E.g. order by, thenby, thenby descending..
|
||||
private readonly SortExpressionBuilder<TRow> _sortExpression;
|
||||
|
||||
private readonly Func<TRow, TRow> _selector;
|
||||
|
||||
#region Properties
|
||||
|
||||
internal override Type ElementType
|
||||
{
|
||||
get
|
||||
{
|
||||
return typeof(TRow);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
internal IEnumerable<TRow> EnumerableRows
|
||||
{
|
||||
get
|
||||
{
|
||||
return _enumerableRows;
|
||||
}
|
||||
}
|
||||
|
||||
internal override DataTable Table
|
||||
{
|
||||
get
|
||||
{
|
||||
return _table;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Constructors
|
||||
|
||||
/// <summary>
|
||||
/// This constructor is used when Select operator is called with output Type other than input row Type.
|
||||
/// Basically fail on GetLDV(), but other LINQ operators must work.
|
||||
/// </summary>
|
||||
internal EnumerableRowCollection(IEnumerable<TRow> enumerableRows, bool isDataViewable, DataTable table)
|
||||
{
|
||||
Debug.Assert(!isDataViewable || table != null, "isDataViewable bug table is null");
|
||||
|
||||
_enumerableRows = enumerableRows;
|
||||
if (isDataViewable)
|
||||
{
|
||||
_table = table;
|
||||
}
|
||||
_listOfPredicates = new List<Func<TRow, bool>>();
|
||||
_sortExpression = new SortExpressionBuilder<TRow>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Basic Constructor
|
||||
/// </summary>
|
||||
internal EnumerableRowCollection(DataTable table)
|
||||
{
|
||||
_table = table;
|
||||
_enumerableRows = table.Rows.Cast<TRow>();
|
||||
_listOfPredicates = new List<Func<TRow, bool>>();
|
||||
_sortExpression = new SortExpressionBuilder<TRow>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Copy Constructor that sets the input IEnumerable as enumerableRows
|
||||
/// Used to maintain IEnumerable that has linq operators executed in the same order as the user
|
||||
/// </summary>
|
||||
internal EnumerableRowCollection(EnumerableRowCollection<TRow> source, IEnumerable<TRow> enumerableRows, Func<TRow, TRow> selector)
|
||||
{
|
||||
Debug.Assert(null != enumerableRows, "null enumerableRows");
|
||||
|
||||
_enumerableRows = enumerableRows;
|
||||
_selector = selector;
|
||||
if (null != source)
|
||||
{
|
||||
if (null == source._selector)
|
||||
{
|
||||
_table = source._table;
|
||||
}
|
||||
_listOfPredicates = new List<Func<TRow, bool>>(source._listOfPredicates);
|
||||
_sortExpression = source._sortExpression.Clone(); //deep copy the List
|
||||
}
|
||||
else
|
||||
{
|
||||
_listOfPredicates = new List<Func<TRow, bool>>();
|
||||
_sortExpression = new SortExpressionBuilder<TRow>();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Constructors
|
||||
|
||||
#region PublicInterface
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method returns an strongly typed iterator
|
||||
/// for the underlying DataRow collection.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// A strongly typed iterator.
|
||||
/// </returns>
|
||||
public IEnumerator<TRow> GetEnumerator()
|
||||
{
|
||||
return _enumerableRows.GetEnumerator();
|
||||
}
|
||||
#endregion PublicInterface
|
||||
|
||||
/// <summary>
|
||||
/// Evaluates filter and sort if necessary and returns
|
||||
/// a LinqDataView representing the LINQ query this class has collected.
|
||||
/// </summary>
|
||||
/// <returns>LinqDataView repesenting the LINQ query</returns>
|
||||
internal LinqDataView GetLinqDataView() //Called by AsLinqDataView
|
||||
{
|
||||
if ((null == _table) || !typeof(DataRow).IsAssignableFrom(typeof(TRow)))
|
||||
{
|
||||
throw DataSetUtil.NotSupported(Strings.ToLDVUnsupported);
|
||||
}
|
||||
|
||||
LinqDataView view = null;
|
||||
|
||||
#region BuildSinglePredicate
|
||||
|
||||
Func<DataRow, bool> finalPredicate = null; //Conjunction of all .Where(..) predicates
|
||||
if ((null != _selector) && (0 < _listOfPredicates.Count))
|
||||
{
|
||||
// Hook up all individual predicates into one predicate
|
||||
// This delegate is a conjunction of multiple predicates set by the user
|
||||
// Note: This is a Short-Circuit Conjunction
|
||||
finalPredicate =
|
||||
delegate(DataRow row)
|
||||
{
|
||||
if (!Object.ReferenceEquals(row, _selector((TRow)(object)row)))
|
||||
{
|
||||
throw DataSetUtil.NotSupported(Strings.ToLDVUnsupported);
|
||||
}
|
||||
foreach (Func<TRow, bool> pred in _listOfPredicates)
|
||||
{
|
||||
if (!pred((TRow)(object)row))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
else if (null != _selector)
|
||||
{
|
||||
finalPredicate =
|
||||
delegate(DataRow row)
|
||||
{
|
||||
if (!Object.ReferenceEquals(row, _selector((TRow)(object)row)))
|
||||
{
|
||||
throw DataSetUtil.NotSupported(Strings.ToLDVUnsupported);
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
else if (0 < _listOfPredicates.Count)
|
||||
{
|
||||
finalPredicate =
|
||||
delegate(DataRow row)
|
||||
{
|
||||
foreach (Func<TRow, bool> pred in _listOfPredicates)
|
||||
{
|
||||
if (!pred((TRow)(object)row))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
}
|
||||
#endregion BuildSinglePredicate
|
||||
|
||||
#region Evaluate Filter/Sort
|
||||
// All of this mess below is because we want to create index only once.
|
||||
//
|
||||
// If we only have filter, we set _view.Predicate - 1 index creation
|
||||
// If we only have sort, we set _view.SortExpression() - 1 index creation
|
||||
// If we have BOTH, we set them through the constructor - 1 index creation
|
||||
//
|
||||
|
||||
// Filter AND Sort
|
||||
if ((null != finalPredicate) && (0 < _sortExpression.Count))
|
||||
{
|
||||
// A lot more work here because constructor does not know type K,
|
||||
// so the responsibility to create appropriate delegate comparers
|
||||
// is outside of the constructor.
|
||||
|
||||
view = new LinqDataView(
|
||||
_table,
|
||||
finalPredicate, //Func() Predicate
|
||||
delegate(DataRow row) //System.Predicate
|
||||
{
|
||||
return finalPredicate(row);
|
||||
},
|
||||
delegate(DataRow a, DataRow b) //Comparison for DV for Index creation
|
||||
{
|
||||
return _sortExpression.Compare(
|
||||
_sortExpression.Select((TRow)(object)a),
|
||||
_sortExpression.Select((TRow)(object)b)
|
||||
);
|
||||
},
|
||||
delegate(object key, DataRow row) //Comparison_K_T for DV's Find()
|
||||
{
|
||||
return _sortExpression.Compare(
|
||||
(List<object>)key,
|
||||
_sortExpression.Select((TRow)(object)row)
|
||||
);
|
||||
},
|
||||
_sortExpression.CloneCast<DataRow>());
|
||||
}
|
||||
else if (null != finalPredicate)
|
||||
{
|
||||
//Only Filtering
|
||||
view = new LinqDataView(
|
||||
_table,
|
||||
finalPredicate,
|
||||
delegate(DataRow row) //System.Predicate
|
||||
{
|
||||
return finalPredicate(row);
|
||||
},
|
||||
null,
|
||||
null,
|
||||
_sortExpression.CloneCast<DataRow>());
|
||||
}
|
||||
else if (0 < _sortExpression.Count)
|
||||
{
|
||||
//Only Sorting
|
||||
view = new LinqDataView(
|
||||
_table,
|
||||
null,
|
||||
null,
|
||||
delegate(DataRow a, DataRow b)
|
||||
{
|
||||
return _sortExpression.Compare(_sortExpression.Select((TRow)(object)a), _sortExpression.Select((TRow)(object)b));
|
||||
},
|
||||
delegate(object key, DataRow row)
|
||||
{
|
||||
return _sortExpression.Compare((List<object>)key, _sortExpression.Select((TRow)(object)row));
|
||||
},
|
||||
_sortExpression.CloneCast<DataRow>());
|
||||
}
|
||||
else
|
||||
{
|
||||
view = new LinqDataView(_table, _sortExpression.CloneCast<DataRow>());
|
||||
}
|
||||
#endregion Evaluate Filter and Sort
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
|
||||
#region Add Single Filter/Sort Expression
|
||||
|
||||
/// <summary>
|
||||
/// Used to add a filter predicate.
|
||||
/// A conjunction of all predicates are evaluated in LinqDataView
|
||||
/// </summary>
|
||||
internal void AddPredicate(Func<TRow, bool> pred)
|
||||
{
|
||||
Debug.Assert(pred != null);
|
||||
_listOfPredicates.Add(pred);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a sort expression when Keyselector is provided but not Comparer
|
||||
/// </summary>
|
||||
internal void AddSortExpression<TKey>(Func<TRow, TKey> keySelector, bool isDescending, bool isOrderBy)
|
||||
{
|
||||
AddSortExpression<TKey>(keySelector, Comparer<TKey>.Default, isDescending, isOrderBy);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a sort expression when Keyselector and Comparer are provided.
|
||||
/// </summary>
|
||||
internal void AddSortExpression<TKey>(
|
||||
Func<TRow, TKey> keySelector,
|
||||
IComparer<TKey> comparer,
|
||||
bool isDescending,
|
||||
bool isOrderBy)
|
||||
{
|
||||
DataSetUtil.CheckArgumentNull(keySelector, "keySelector");
|
||||
DataSetUtil.CheckArgumentNull(comparer, "comparer");
|
||||
|
||||
_sortExpression.Add(
|
||||
delegate(TRow input)
|
||||
{
|
||||
return (object)keySelector(input);
|
||||
},
|
||||
delegate(object val1, object val2)
|
||||
{
|
||||
return (isDescending ? -1 : 1) * comparer.Compare((TKey)val1, (TKey)val2);
|
||||
},
|
||||
isOrderBy);
|
||||
}
|
||||
|
||||
#endregion Add Single Filter/Sort Expression
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,212 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="EnumRowCollectionExtensions.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Globalization;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// This static class defines the extension methods that add LINQ operator functionality
|
||||
/// within IEnumerableDT and IOrderedEnumerableDT.
|
||||
/// </summary>
|
||||
public static class EnumerableRowCollectionExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// LINQ's Where operator for generic EnumerableRowCollection.
|
||||
/// </summary>
|
||||
public static EnumerableRowCollection<TRow> Where<TRow>(
|
||||
this EnumerableRowCollection<TRow> source,
|
||||
Func<TRow, bool> predicate)
|
||||
{
|
||||
EnumerableRowCollection<TRow> edt =
|
||||
new EnumerableRowCollection<TRow>(source, Enumerable.Where<TRow>(source, predicate), null); //copy constructor
|
||||
edt.AddPredicate(predicate);
|
||||
return edt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LINQ's OrderBy operator for generic EnumerableRowCollection.
|
||||
/// </summary>
|
||||
public static OrderedEnumerableRowCollection<TRow> OrderBy<TRow, TKey>(
|
||||
this EnumerableRowCollection<TRow> source,
|
||||
Func<TRow, TKey> keySelector)
|
||||
{
|
||||
IEnumerable<TRow> ie = Enumerable.OrderBy<TRow, TKey>(source, keySelector);
|
||||
|
||||
OrderedEnumerableRowCollection<TRow> edt = new OrderedEnumerableRowCollection<TRow>(source, ie);
|
||||
edt.AddSortExpression(keySelector, false, true);
|
||||
return edt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LINQ's OrderBy operator for generic EnumerableRowCollection.
|
||||
/// </summary>
|
||||
public static OrderedEnumerableRowCollection<TRow> OrderBy<TRow, TKey>(
|
||||
this EnumerableRowCollection<TRow> source,
|
||||
Func<TRow, TKey> keySelector,
|
||||
IComparer<TKey> comparer)
|
||||
{
|
||||
IEnumerable<TRow> ie = Enumerable.OrderBy<TRow, TKey>(source, keySelector, comparer);
|
||||
OrderedEnumerableRowCollection<TRow> edt = new OrderedEnumerableRowCollection<TRow>(source, ie);
|
||||
edt.AddSortExpression(keySelector, comparer, false, true);
|
||||
return edt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LINQ's OrderByDescending operator for generic EnumerableRowCollection.
|
||||
/// </summary>
|
||||
public static OrderedEnumerableRowCollection<TRow> OrderByDescending<TRow, TKey>(
|
||||
this EnumerableRowCollection<TRow> source,
|
||||
Func<TRow, TKey> keySelector)
|
||||
{
|
||||
IEnumerable<TRow> ie = Enumerable.OrderByDescending<TRow, TKey>(source, keySelector);
|
||||
|
||||
OrderedEnumerableRowCollection<TRow> edt = new OrderedEnumerableRowCollection<TRow>(source, ie);
|
||||
edt.AddSortExpression(keySelector, true, true);
|
||||
return edt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LINQ's OrderByDescending operator for generic EnumerableRowCollection.
|
||||
/// </summary>
|
||||
public static OrderedEnumerableRowCollection<TRow> OrderByDescending<TRow, TKey>(
|
||||
this EnumerableRowCollection<TRow> source,
|
||||
Func<TRow, TKey> keySelector,
|
||||
IComparer<TKey> comparer)
|
||||
{
|
||||
IEnumerable<TRow> ie = Enumerable.OrderByDescending<TRow, TKey>(source, keySelector, comparer);
|
||||
|
||||
OrderedEnumerableRowCollection<TRow> edt = new OrderedEnumerableRowCollection<TRow>(source, ie);
|
||||
edt.AddSortExpression(keySelector, comparer, true, true);
|
||||
return edt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LINQ's ThenBy operator for generic EnumerableRowCollection.
|
||||
/// </summary>
|
||||
public static OrderedEnumerableRowCollection<TRow> ThenBy<TRow, TKey>(
|
||||
this OrderedEnumerableRowCollection<TRow> source,
|
||||
Func<TRow, TKey> keySelector)
|
||||
{
|
||||
IEnumerable<TRow> ie =
|
||||
Enumerable.ThenBy<TRow, TKey>((IOrderedEnumerable<TRow>)source.EnumerableRows, keySelector);
|
||||
|
||||
OrderedEnumerableRowCollection<TRow> edt =
|
||||
new OrderedEnumerableRowCollection<TRow>((EnumerableRowCollection<TRow>)source, ie);
|
||||
|
||||
edt.AddSortExpression(keySelector, /*isDesc*/ false, /*isOrderBy*/ false);
|
||||
return edt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LINQ's ThenBy operator for generic EnumerableRowCollection.
|
||||
/// </summary>
|
||||
public static OrderedEnumerableRowCollection<TRow> ThenBy<TRow, TKey>(
|
||||
this OrderedEnumerableRowCollection<TRow> source,
|
||||
Func<TRow, TKey> keySelector,
|
||||
IComparer<TKey> comparer)
|
||||
{
|
||||
IEnumerable<TRow> ie =
|
||||
Enumerable.ThenBy<TRow, TKey>((IOrderedEnumerable<TRow>)source.EnumerableRows, keySelector, comparer);
|
||||
|
||||
OrderedEnumerableRowCollection<TRow> edt =
|
||||
new OrderedEnumerableRowCollection<TRow>((EnumerableRowCollection<TRow>)source, ie);
|
||||
|
||||
edt.AddSortExpression(keySelector, comparer, false, false);
|
||||
return edt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LINQ's ThenByDescending operator for generic EnumerableRowCollection.
|
||||
/// </summary>
|
||||
public static OrderedEnumerableRowCollection<TRow> ThenByDescending<TRow, TKey>(
|
||||
this OrderedEnumerableRowCollection<TRow> source,
|
||||
Func<TRow, TKey> keySelector)
|
||||
{
|
||||
IEnumerable<TRow> ie =
|
||||
Enumerable.ThenByDescending<TRow, TKey>((IOrderedEnumerable<TRow>)source.EnumerableRows, keySelector);
|
||||
|
||||
OrderedEnumerableRowCollection<TRow> edt =
|
||||
new OrderedEnumerableRowCollection<TRow>((EnumerableRowCollection<TRow>)source, ie);
|
||||
|
||||
edt.AddSortExpression(keySelector, /*desc*/ true, false);
|
||||
return edt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LINQ's ThenByDescending operator for generic EnumerableRowCollection.
|
||||
/// </summary>
|
||||
public static OrderedEnumerableRowCollection<TRow> ThenByDescending<TRow, TKey>(
|
||||
this OrderedEnumerableRowCollection<TRow> source,
|
||||
Func<TRow, TKey> keySelector,
|
||||
IComparer<TKey> comparer)
|
||||
{
|
||||
IEnumerable<TRow> ie =
|
||||
Enumerable.ThenByDescending<TRow, TKey>((IOrderedEnumerable<TRow>)source.EnumerableRows, keySelector, comparer);
|
||||
|
||||
OrderedEnumerableRowCollection<TRow> edt =
|
||||
new OrderedEnumerableRowCollection<TRow>((EnumerableRowCollection<TRow>)source, ie);
|
||||
|
||||
edt.AddSortExpression(keySelector, comparer, true, false);
|
||||
return edt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Executes a Select (Projection) on EnumerableDataTable. If the selector returns a different
|
||||
/// type than the type of rows, then AsLinqDataView is disabled, and the returning EnumerableDataTable
|
||||
/// represents an enumerable over the LINQ Query.
|
||||
/// </summary>
|
||||
public static EnumerableRowCollection<S> Select<TRow, S>(
|
||||
this EnumerableRowCollection<TRow> source,
|
||||
Func<TRow, S> selector)
|
||||
{
|
||||
//Anonymous type or some other type
|
||||
//The only thing that matters from this point on is _enumerableRows
|
||||
|
||||
IEnumerable<S> typedEnumerable = Enumerable.Select<TRow, S>(source, selector);
|
||||
|
||||
// Dont need predicates or sort expression from this point on since we know
|
||||
// AsLinqDataView is disabled.
|
||||
return new EnumerableRowCollection<S>(((object)source) as EnumerableRowCollection<S>,
|
||||
typedEnumerable,
|
||||
((object)selector) as Func<S,S>);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Casts an EnumerableDataTable_TSource into EnumerableDataTable_TResult
|
||||
/// </summary>
|
||||
public static EnumerableRowCollection<TResult> Cast<TResult>(this EnumerableRowCollection source)
|
||||
{
|
||||
// Since Cast does not have the signature Cast_T_R(..) this call is routed
|
||||
// through the non-generic base class EnumerableDataTable
|
||||
|
||||
if ((null != source) && source.ElementType.Equals(typeof(TResult)))
|
||||
{
|
||||
return (EnumerableRowCollection<TResult>)(object)source;
|
||||
}
|
||||
else
|
||||
{ //Anonymous type or some other type
|
||||
//The only thing that matters from this point on is _enumerableRows
|
||||
|
||||
IEnumerable<TResult> typedEnumerable = Enumerable.Cast<TResult>(source);
|
||||
|
||||
EnumerableRowCollection<TResult> newEdt = new EnumerableRowCollection<TResult>(
|
||||
typedEnumerable,
|
||||
typeof(TResult).IsAssignableFrom(source.ElementType) && typeof(DataRow).IsAssignableFrom(typeof(TResult)),
|
||||
source.Table);
|
||||
|
||||
return newEdt;
|
||||
}
|
||||
}
|
||||
} //end class
|
||||
}
|
||||
@@ -0,0 +1,305 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="LinqDataView.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Text;
|
||||
using System.Data.DataSetExtensions;
|
||||
|
||||
namespace System.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a bindable, queryable DataView of DataRow, that can be created from from LINQ queries over DataTable
|
||||
/// and from DataTable.
|
||||
/// </summary>
|
||||
internal class LinqDataView : DataView, IBindingList, IBindingListView
|
||||
{
|
||||
/// <summary>
|
||||
/// A Comparer that compares a Key and a Row.
|
||||
/// </summary>
|
||||
internal Func<object, DataRow, int> comparerKeyRow; // comparer for DataView.Find(..
|
||||
|
||||
/// <summary>
|
||||
/// Builds the sort expression in case multiple selector/comparers are added
|
||||
/// </summary>
|
||||
internal readonly SortExpressionBuilder<DataRow> sortExpressionBuilder;
|
||||
|
||||
/// <summary>
|
||||
/// Constructs a LinkDataView and its parent DataView.
|
||||
/// Does not create index on the DataView since filter and sort expressions are not yet provided.
|
||||
/// </summary>
|
||||
/// <param name="table">The input table from which LinkDataView is to be created.</param>
|
||||
internal LinqDataView(DataTable table, SortExpressionBuilder<DataRow> sortExpressionBuilder)
|
||||
: base(table)
|
||||
{
|
||||
Debug.Assert(table != null, "null DataTable");
|
||||
this.sortExpressionBuilder = sortExpressionBuilder ?? new SortExpressionBuilder<DataRow>();
|
||||
}
|
||||
|
||||
|
||||
//I have two forms of predicate because I need to pass in null if predicate is null. Otherwise I need to convert it into delegate and pass it into
|
||||
// data view's constructor. That logic for checking null can't be embedded in the base constructor call.
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <param name="table">Table from which to create the view</param>
|
||||
/// <param name="predicate_func">User-provided filter-predicate as a Func<DataRow>, bool>"/></param>
|
||||
/// <param name="predicate_system">User-provided predicate but in the form of System.Predicate<DataRow>
|
||||
/// Predicates are being replicated in different forms so that nulls can be passed in.
|
||||
/// For e.g. when user provides null predicate, base.Predicate should be set to null. I cant do that in the constructor initialization
|
||||
/// if I will have to create System.Predicate delegate from Func.
|
||||
/// </param>
|
||||
/// <param name="comparison">The comparer function of DataRow to be used for sorting. </param>
|
||||
/// <param name="comparerKeyRow">A comparer function that compares a Key value to DataRow.</param>
|
||||
/// <param name="isDescending">Whether sorting is ascending or descending.</param>
|
||||
/// <param name="rowState">Row state filter. For the purpose of LinkDataView it should always be CurrentRows.</param>
|
||||
internal LinqDataView(
|
||||
DataTable table,
|
||||
Func<DataRow, bool> predicate_func,
|
||||
Predicate<DataRow> predicate_system,
|
||||
Comparison<DataRow> comparison,
|
||||
Func<object, DataRow, int> comparerKeyRow,
|
||||
SortExpressionBuilder<DataRow> sortExpressionBuilder)
|
||||
|
||||
//Parent constructor
|
||||
: base(table,
|
||||
predicate_system,
|
||||
comparison,
|
||||
DataViewRowState.CurrentRows)
|
||||
{
|
||||
this.sortExpressionBuilder = (sortExpressionBuilder == null) ? this.sortExpressionBuilder : sortExpressionBuilder;
|
||||
this.comparerKeyRow = comparerKeyRow;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the expression used to filter which rows are viewed in the LinqDataView
|
||||
/// </summary>
|
||||
public override string RowFilter
|
||||
{
|
||||
get
|
||||
{
|
||||
if (base.RowPredicate == null)//using string based filter or no filter
|
||||
{
|
||||
return base.RowFilter;
|
||||
}
|
||||
else //using expression based filter
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
base.RowPredicate = null;
|
||||
base.RowFilter = String.Empty; //INDEX rebuild twice
|
||||
}
|
||||
else
|
||||
{
|
||||
base.RowFilter = value;
|
||||
base.RowPredicate = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#region Find
|
||||
|
||||
/// <summary>
|
||||
/// Searches the index and finds a single row where the sort-key matches the input key
|
||||
/// </summary>
|
||||
/// <param name="key">Value of the key to find</param>
|
||||
/// <returns>Index of the first match of input key</returns>
|
||||
internal override int FindByKey(object key)
|
||||
{
|
||||
/////////////// Preconditions ////////////////
|
||||
//check that both string and expression based sort are never simultaneously set
|
||||
Debug.Assert(base.Sort != null);
|
||||
Debug.Assert(!(!String.IsNullOrEmpty(base.Sort) && base.SortComparison != null));
|
||||
/////////////////////////////////////////////
|
||||
|
||||
if (!String.IsNullOrEmpty(base.Sort)) //use find for DV's sort string
|
||||
{
|
||||
return base.FindByKey(key);
|
||||
}
|
||||
else if (base.SortComparison == null) //neither string or expr set
|
||||
{
|
||||
//This is the exception message from DataView that we want to use
|
||||
throw ExceptionBuilder.IndexKeyLength(0, 0);
|
||||
}
|
||||
else //find for expression based sort
|
||||
{
|
||||
if (sortExpressionBuilder.Count !=1)
|
||||
throw DataSetUtil.InvalidOperation(Strings.LDV_InvalidNumOfKeys(sortExpressionBuilder.Count));
|
||||
|
||||
Index.ComparisonBySelector<object, DataRow> compareDelg =
|
||||
new Index.ComparisonBySelector<object, DataRow>(comparerKeyRow);
|
||||
|
||||
List<object> keyList = new List<object>();
|
||||
keyList.Add(key);
|
||||
Range range = FindRecords<object, DataRow>(compareDelg, keyList);
|
||||
|
||||
return (range.Count == 0) ? -1 : range.Min;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Since LinkDataView does not support multiple selectors/comparers, it does not make sense for
|
||||
/// them to Find using multiple keys.
|
||||
/// This overriden method prevents users calling multi-key find on dataview.
|
||||
/// </summary>
|
||||
internal override int FindByKey(object[] key)
|
||||
{
|
||||
//---------Checks ----------------
|
||||
//must have string or expression based sort specified
|
||||
if (base.SortComparison == null && String.IsNullOrEmpty(base.Sort))
|
||||
{
|
||||
//This is the exception message from DataView that we want to use
|
||||
throw ExceptionBuilder.IndexKeyLength(0, 0);
|
||||
}
|
||||
else if (base.SortComparison != null && key.Length != sortExpressionBuilder.Count)
|
||||
{
|
||||
throw DataSetUtil.InvalidOperation(Strings.LDV_InvalidNumOfKeys(sortExpressionBuilder.Count));
|
||||
}
|
||||
//--------------------------------
|
||||
|
||||
if (base.SortComparison == null)//using string to sort
|
||||
return base.FindByKey(key);
|
||||
else
|
||||
{
|
||||
Index.ComparisonBySelector<object, DataRow> compareDelg =
|
||||
new Index.ComparisonBySelector<object, DataRow>(comparerKeyRow);
|
||||
|
||||
List<object> keyList = new List<object>();
|
||||
foreach (object singleKey in key)
|
||||
{
|
||||
keyList.Add(singleKey);
|
||||
}
|
||||
Range range = FindRecords<object, DataRow>(compareDelg, keyList);
|
||||
return (range.Count == 0) ? -1 : range.Min;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Searches the index and finds rows where the sort-key matches the input key.
|
||||
/// Since LinkDataView does not support multiple selectors/comparers, it does not make sense for
|
||||
/// them to Find using multiple keys. This overriden method prevents users calling multi-key find on dataview.
|
||||
/// </summary>
|
||||
internal override DataRowView[] FindRowsByKey(object[] key)
|
||||
{
|
||||
//---------Checks ----------------
|
||||
//must have string or expression based sort specified
|
||||
if (base.SortComparison == null && String.IsNullOrEmpty(base.Sort))
|
||||
{
|
||||
//This is the exception message from DataView that we want to use
|
||||
throw ExceptionBuilder.IndexKeyLength(0, 0);
|
||||
}
|
||||
else if (base.SortComparison != null && key.Length != sortExpressionBuilder.Count)
|
||||
{
|
||||
throw DataSetUtil.InvalidOperation(Strings.LDV_InvalidNumOfKeys(sortExpressionBuilder.Count));
|
||||
}
|
||||
//--------------------------------
|
||||
|
||||
if (base.SortComparison == null)//using string to sort
|
||||
{
|
||||
return base.FindRowsByKey(key);
|
||||
}
|
||||
else
|
||||
{
|
||||
Range range = FindRecords<object, DataRow>(
|
||||
new Index.ComparisonBySelector<object, DataRow>(comparerKeyRow),
|
||||
new List<object>(key));
|
||||
return base.GetDataRowViewFromRange(range);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
#region Misc Overrides
|
||||
/// <summary>
|
||||
/// Overriding DataView's SetIndex to prevent users from setting RowState filter to anything other
|
||||
/// than CurrentRows.
|
||||
/// </summary>
|
||||
internal override void SetIndex(string newSort, DataViewRowState newRowStates, IFilter newRowFilter)
|
||||
{
|
||||
//Throw only if expressions (filter or sort) are used and rowstate is not current rows
|
||||
if ( (base.SortComparison != null || base.RowPredicate != null)
|
||||
&& newRowStates != DataViewRowState.CurrentRows)
|
||||
{
|
||||
throw DataSetUtil.Argument(Strings.LDVRowStateError);
|
||||
}
|
||||
else
|
||||
{
|
||||
base.SetIndex(newSort, newRowStates, newRowFilter);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IBindingList
|
||||
|
||||
/// <summary>
|
||||
/// Clears both expression-based and DataView's string-based sorting.
|
||||
/// </summary>
|
||||
void IBindingList.RemoveSort()
|
||||
{
|
||||
base.Sort = String.Empty;
|
||||
base.SortComparison = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides IBindingList's SortProperty so that it returns null if expression based sort
|
||||
/// is used in the LinkDataView, otherwise it defers the result to DataView
|
||||
/// </summary>
|
||||
PropertyDescriptor IBindingList.SortProperty
|
||||
{
|
||||
get
|
||||
{
|
||||
return (base.SortComparison == null) ? base.GetSortProperty() : null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides IBindingList's SortDescriptions so that it returns null if expression based sort
|
||||
/// is used in the LinkDataView, otherwise it defers the result to DataView
|
||||
/// </summary>
|
||||
ListSortDescriptionCollection IBindingListView.SortDescriptions
|
||||
{
|
||||
get
|
||||
{
|
||||
if (base.SortComparison == null)
|
||||
{
|
||||
return base.GetSortDescriptions();
|
||||
}
|
||||
else
|
||||
{
|
||||
return new ListSortDescriptionCollection();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tells whether the LinqDataView is sorted or not
|
||||
/// </summary>
|
||||
bool IBindingList.IsSorted
|
||||
{
|
||||
get
|
||||
{ //Sorted if either expression based sort or string based sort is set
|
||||
return !(base.SortComparison == null && base.Sort.Length == 0);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="OrderedEnumerableRowCollection.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System.Text;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.Data
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This class provides a wrapper for DataTables representing an ordered sequence.
|
||||
/// </summary>
|
||||
public sealed class OrderedEnumerableRowCollection<TRow> : EnumerableRowCollection<TRow>
|
||||
{
|
||||
/// <summary>
|
||||
/// Copy Constructor that sets enumerableRows to the one given in the input
|
||||
/// </summary>
|
||||
internal OrderedEnumerableRowCollection(EnumerableRowCollection<TRow> enumerableTable, IEnumerable<TRow> enumerableRows)
|
||||
: base(enumerableTable, enumerableRows, null)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="ShippingAssemblyAttribute.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">markash</owner>
|
||||
// <owner current="true" primary="false">stevesta</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
[assembly: System.Security.SecurityCritical]
|
||||
@@ -0,0 +1,209 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="EnumerableDataTable.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System.Text;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.Data
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This class represents a combined sort expression build using mutiple sort expressions.
|
||||
/// </summary>
|
||||
/// <typeparam name="T"></typeparam>
|
||||
internal class SortExpressionBuilder<T> : IComparer<List<object>>
|
||||
{
|
||||
/**
|
||||
* This class ensures multiple orderby/thenbys are handled correctly. Its semantics is as follows:
|
||||
*
|
||||
* Query 1:
|
||||
* orderby a
|
||||
* thenby b
|
||||
* orderby c
|
||||
* orderby d
|
||||
* thenby e
|
||||
*
|
||||
* is equivalent to:
|
||||
*
|
||||
* Query 2:
|
||||
* orderby d
|
||||
* thenby e
|
||||
* thenby c
|
||||
* thenby a
|
||||
* thenby b
|
||||
*
|
||||
**/
|
||||
|
||||
//Selectors and comparers are mapped using the index in the list.
|
||||
//E.g: _comparers[i] is used with _selectors[i]
|
||||
|
||||
LinkedList<Func<T, object>> _selectors = new LinkedList<Func<T, object>>();
|
||||
LinkedList<Comparison<object>> _comparers = new LinkedList<Comparison<object>>();
|
||||
|
||||
LinkedListNode<Func<T, object>> _currentSelector = null;
|
||||
LinkedListNode<Comparison<object>> _currentComparer = null;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Adds a sorting selector/comparer in the correct order
|
||||
/// </summary>
|
||||
internal void Add(Func<T, object> keySelector, Comparison<object> compare, bool isOrderBy)
|
||||
{
|
||||
Debug.Assert(keySelector != null);
|
||||
Debug.Assert(compare != null);
|
||||
//Inputs are assumed to be valid. The burden for ensuring it is on the caller.
|
||||
|
||||
if (isOrderBy)
|
||||
{
|
||||
_currentSelector = _selectors.AddFirst(keySelector);
|
||||
_currentComparer = _comparers.AddFirst(compare);
|
||||
}
|
||||
else
|
||||
{
|
||||
//ThenBy can only be called after OrderBy
|
||||
Debug.Assert(_currentSelector != null);
|
||||
Debug.Assert(_currentComparer != null);
|
||||
|
||||
_currentSelector = _selectors.AddAfter(_currentSelector, keySelector);
|
||||
_currentComparer = _comparers.AddAfter(_currentComparer, compare);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Combined selector of all selectors added thusfar.
|
||||
/// </summary>
|
||||
/// <returns>List of 'objects returned by each selector'. This list is the combined-selector</returns>
|
||||
public List<object> Select(T row)
|
||||
{
|
||||
List<object> result = new List<object>();
|
||||
|
||||
foreach (Func<T, object> selector in _selectors)
|
||||
{
|
||||
result.Add(selector(row));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Represents a Comparer (of IComparer) that compares two combined-selectors using
|
||||
/// provided comparers for each individual selector.
|
||||
/// Note: Comparison is done in the order it was Added.
|
||||
/// </summary>
|
||||
/// <returns>Comparison result of the combined Sort comparer expression</returns>
|
||||
public int Compare(List<object> a, List<object> b)
|
||||
{
|
||||
Debug.Assert(a.Count == Count);
|
||||
|
||||
int i = 0;
|
||||
foreach (Comparison<object> compare in _comparers)
|
||||
{
|
||||
int result = compare(a[i], b[i]);
|
||||
|
||||
if (result != 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal int Count
|
||||
{
|
||||
get
|
||||
{
|
||||
Debug.Assert(_selectors.Count == _comparers.Count); //weak now that we have two dimensions
|
||||
return _selectors.Count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clones the SortexpressionBuilder and returns a new object
|
||||
/// that points to same comparer and selectors (in the same order).
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
internal SortExpressionBuilder<T> Clone()
|
||||
{
|
||||
SortExpressionBuilder<T> builder = new SortExpressionBuilder<T>();
|
||||
|
||||
foreach (Func<T, object> selector in _selectors)
|
||||
{
|
||||
if (selector == _currentSelector.Value)
|
||||
{
|
||||
builder._currentSelector = builder._selectors.AddLast(selector);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder._selectors.AddLast(selector);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach (Comparison<object> comparer in _comparers)
|
||||
{
|
||||
if (comparer == _currentComparer.Value)
|
||||
{
|
||||
builder._currentComparer = builder._comparers.AddLast(comparer);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder._comparers.AddLast(comparer);
|
||||
}
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clones the SortExpressinBuilder and casts to type TResult.
|
||||
/// </summary>
|
||||
internal SortExpressionBuilder<TResult> CloneCast<TResult>()
|
||||
{
|
||||
SortExpressionBuilder<TResult> builder = new SortExpressionBuilder<TResult>();
|
||||
|
||||
foreach (Func<T, object> selector in _selectors)
|
||||
{
|
||||
if (selector == _currentSelector.Value)
|
||||
{
|
||||
builder._currentSelector = builder._selectors.AddLast(r => selector((T)(object)r));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder._selectors.AddLast(r => selector((T)(object)r));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
foreach (Comparison<object> comparer in _comparers)
|
||||
{
|
||||
if (comparer == _currentComparer.Value)
|
||||
{
|
||||
builder._currentComparer = builder._comparers.AddLast(comparer);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder._comparers.AddLast(comparer);
|
||||
}
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
} //end SortExpressionBuilder<T>
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="TypedTableBase.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">spather</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Runtime.Serialization;
|
||||
|
||||
namespace System.Data {
|
||||
|
||||
/// <summary>
|
||||
/// This is the generic base class for TypedDataSet
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public abstract class TypedTableBase<T> : DataTable, IEnumerable<T> where T : DataRow {
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor for generic TypedTableBase.
|
||||
/// Will be called by generated Typed DataSet classes and is not for public use.
|
||||
/// </summary>
|
||||
protected TypedTableBase() : base() {}
|
||||
|
||||
/// <summary>
|
||||
/// Constructor for the generic TypedTableBase with takes SerializationInfo and StreamingContext.
|
||||
/// Will be called by generated Typed DataSet classes and
|
||||
/// is not for public use.
|
||||
/// </summary>
|
||||
/// <param name="info">
|
||||
/// SerializationInfo containing data to construct the object.
|
||||
/// </param>
|
||||
/// <param name="context">
|
||||
/// The streaming context for the object being deserializad.
|
||||
/// </param>
|
||||
protected TypedTableBase(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
|
||||
: base(info, context) {}
|
||||
|
||||
/// <summary>
|
||||
/// This property returns a enumerator of T for the TypedTable. Note, this could
|
||||
/// execute the underlying Linq expression.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// IEnumerable of T.
|
||||
/// </returns>
|
||||
public IEnumerator<T> GetEnumerator() {
|
||||
return this.Rows.Cast<T>().GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Casts an EnumerableDataTable_TSource into EnumerableDataTable_TResult
|
||||
/// </summary>
|
||||
public EnumerableRowCollection<TResult> Cast<TResult>()
|
||||
{
|
||||
EnumerableRowCollection<T> erc = new EnumerableRowCollection<T>((DataTable)this);
|
||||
return erc.Cast<TResult>();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
//------------------------------------------------------------------------------
|
||||
// <copyright file="EnumRowCollectionExtensions.cs" company="Microsoft">
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// </copyright>
|
||||
// <owner current="true" primary="true">[....]</owner>
|
||||
// <owner current="true" primary="false">[....]</owner>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Globalization;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace System.Data
|
||||
{
|
||||
/// <summary>
|
||||
/// This static class defines the extension methods that add LINQ operator functionality
|
||||
/// within IEnumerableDT and IOrderedEnumerableDT.
|
||||
/// </summary>
|
||||
public static class TypedTableBaseExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// LINQ's Where operator for generic EnumerableRowCollection.
|
||||
/// </summary>
|
||||
public static EnumerableRowCollection<TRow> Where<TRow>(
|
||||
this TypedTableBase<TRow> source,
|
||||
Func<TRow, bool> predicate) where TRow : DataRow
|
||||
{
|
||||
DataSetUtil.CheckArgumentNull(source, "source");
|
||||
EnumerableRowCollection<TRow> erc = new EnumerableRowCollection<TRow>((DataTable)source);
|
||||
return erc.Where<TRow>(predicate);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LINQ's OrderBy operator for generic EnumerableRowCollection.
|
||||
/// </summary>
|
||||
public static OrderedEnumerableRowCollection<TRow> OrderBy<TRow, TKey>(
|
||||
this TypedTableBase<TRow> source,
|
||||
Func<TRow, TKey> keySelector) where TRow : DataRow
|
||||
{
|
||||
DataSetUtil.CheckArgumentNull(source, "source");
|
||||
EnumerableRowCollection<TRow> erc = new EnumerableRowCollection<TRow>((DataTable)source);
|
||||
return erc.OrderBy<TRow, TKey>(keySelector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LINQ's OrderBy operator for generic EnumerableRowCollection.
|
||||
/// </summary>
|
||||
public static OrderedEnumerableRowCollection<TRow> OrderBy<TRow, TKey>(
|
||||
this TypedTableBase<TRow> source,
|
||||
Func<TRow, TKey> keySelector,
|
||||
IComparer<TKey> comparer) where TRow : DataRow
|
||||
{
|
||||
DataSetUtil.CheckArgumentNull(source, "source");
|
||||
EnumerableRowCollection<TRow> erc = new EnumerableRowCollection<TRow>((DataTable)source);
|
||||
return erc.OrderBy<TRow, TKey>(keySelector, comparer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LINQ's OrderByDescending operator for generic EnumerableRowCollection.
|
||||
/// </summary>
|
||||
public static OrderedEnumerableRowCollection<TRow> OrderByDescending<TRow, TKey>(
|
||||
this TypedTableBase<TRow> source,
|
||||
Func<TRow, TKey> keySelector) where TRow : DataRow
|
||||
{
|
||||
DataSetUtil.CheckArgumentNull(source, "source");
|
||||
EnumerableRowCollection<TRow> erc = new EnumerableRowCollection<TRow>((DataTable)source);
|
||||
return erc.OrderByDescending<TRow, TKey>(keySelector);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// LINQ's OrderByDescending operator for generic EnumerableRowCollection.
|
||||
/// </summary>
|
||||
public static OrderedEnumerableRowCollection<TRow> OrderByDescending<TRow, TKey>(
|
||||
this TypedTableBase<TRow> source,
|
||||
Func<TRow, TKey> keySelector,
|
||||
IComparer<TKey> comparer) where TRow : DataRow
|
||||
{
|
||||
DataSetUtil.CheckArgumentNull(source, "source");
|
||||
EnumerableRowCollection<TRow> erc = new EnumerableRowCollection<TRow>((DataTable)source);
|
||||
return erc.OrderByDescending<TRow, TKey>(keySelector, comparer);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Executes a Select (Projection) on EnumerableDataTable. If the selector returns a different
|
||||
/// type than the type of rows, then AsLinqDataView is disabled, and the returning EnumerableDataTable
|
||||
/// represents an enumerable over the LINQ Query.
|
||||
/// </summary>
|
||||
public static EnumerableRowCollection<S> Select<TRow, S>(
|
||||
this TypedTableBase<TRow> source,
|
||||
Func<TRow, S> selector) where TRow : DataRow
|
||||
{
|
||||
DataSetUtil.CheckArgumentNull(source, "source");
|
||||
EnumerableRowCollection<TRow> erc = new EnumerableRowCollection<TRow>((DataTable)source);
|
||||
return erc.Select<TRow, S>(selector);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This method returns a IEnumerable of TRow.
|
||||
/// </summary>
|
||||
/// <param name="source">
|
||||
/// The source DataTable to make enumerable.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// IEnumerable of datarows.
|
||||
/// </returns>
|
||||
public static EnumerableRowCollection<TRow> AsEnumerable<TRow>(this TypedTableBase<TRow> source) where TRow : DataRow
|
||||
{
|
||||
DataSetUtil.CheckArgumentNull(source, "source");
|
||||
return new EnumerableRowCollection<TRow>(source as DataTable);
|
||||
}
|
||||
|
||||
public static TRow ElementAtOrDefault<TRow>(this TypedTableBase<TRow> source, int index) where TRow : DataRow
|
||||
{
|
||||
if ((index >= 0) && (index < source.Rows.Count))
|
||||
{
|
||||
return (TRow)source.Rows[index];
|
||||
}
|
||||
else
|
||||
{
|
||||
return default(TRow);
|
||||
}
|
||||
}
|
||||
|
||||
} //end class
|
||||
}
|
||||
Reference in New Issue
Block a user