using EasyDevCore.Common;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace EasyDevCore.Database.EntityTable
{
///
///
///
public static class DataTableExtensions
{
///
/// Loads the asynchronous.
///
/// The source.
/// The reader.
/// The cancellation token.
public static async Task LoadAsync(this DataTable source, DbDataReader reader, CancellationToken cancellationToken = default)
{
if (reader.IsClosed) return;
int totalRows = source.Rows.Count;
List> mapRcTcColumns = null;
bool isFirst = true;
while (await reader.ReadAsync(cancellationToken).ConfigureAwait(false))
{
if (isFirst)
{
Dictionary readerColumns = new Dictionary(StringComparer.InvariantCultureIgnoreCase);
for (int i = 0; i < reader.FieldCount; i++)
{
readerColumns[reader.GetName(i)] = i;
}
if (source.Columns.Count == 0)
{
for (int col = 0; col < reader.FieldCount; col++)
{
source.Columns.Add(reader.GetName(col), reader.GetFieldType(col));
}
}
mapRcTcColumns = (from rc in readerColumns
join tc in source.Columns.Cast() on rc.Key equals tc.ColumnName
select new Tuple(rc.Value, tc.Ordinal)).ToList();
isFirst = false;
}
var newRow = source.NewRow();
for (int i = 0; i < mapRcTcColumns.Count; i++)
{
newRow[mapRcTcColumns[i].Item2] = reader.GetValue(mapRcTcColumns[i].Item1) ?? DBNull.Value;
}
source.Rows.Add(newRow);
}
bool hasNextResult = await reader.NextResultAsync(cancellationToken).ConfigureAwait(false);
if (!hasNextResult) await reader.CloseAsync().ConfigureAwait(false);
}
///
/// Firsts the or add.
///
/// The type of the source.
/// The source.
///
public static TSource FirstOrAdd(this DataTable source) where TSource : DataRow
{
if (source.Rows.Count == 0)
{
return (TSource)(source as DataTable).DefaultView.AddNew().Row;
}
else
{
return (TSource)(source as DataTable).DefaultView[0].Row;
}
}
///
/// Ases the enumberable.
///
/// The source.
///
public static IEnumerable AsEnumberable(this DataTable source)
{
System.Collections.IEnumerator iterator = source.AsEnumberable().GetEnumerator();
while (iterator.MoveNext())
{
yield return (DataRow)iterator.Current;
}
}
///
/// Adds the new row.
///
/// The source.
///
public static DataRow AddNewRow(this DataTable source)
{
var newRow = source.NewRow();
source.Rows.Add(newRow);
return newRow;
}
///
/// Finds the DataRow.
///
/// The source.
/// The values.
///
public static DataRow FindDataRow(this DataTable source, params object[] values)
{
var argValues = ArgumentHelper.GetArgValues(values);
DataView view = new DataView(source as DataTable, string.Empty, string.Join(",", argValues.Keys), DataViewRowState.CurrentRows);
int rowIndex = view.Find(argValues.Values.ToArray());
return rowIndex == -1 ? null : view[rowIndex].Row;
}
///
/// Gets the index of the specified DataRow object.
///
/// The source.
/// The DataRow.
///
public static int IndexOf(this DataTable source, DataRow DataRow)
{
return source.IndexOf(DataRow);
}
///
/// Gets the matched columns list.
///
/// The source.
/// The dest.
/// The colum names filter (can be use = for mapping; ex: ColumnName = PropertyName).
/// The except column names.
///
internal static IDictionary GetMatchedColumnsList(this DataTable source, DataTable dest, string columnNames = "", string exceptColumnNames = "")
{
bool hasMapping = columnNames.Contains("=");
IEnumerable colNames = columnNames.SplitCommaString(trimSpace: true);
if (columnNames.Contains("*") || string.IsNullOrWhiteSpace(columnNames))
{
colNames = from s in source.Columns.OfType()
join d in dest.Columns.OfType() on s.ColumnName equals d.ColumnName
select s.ColumnName;
}
HashSet exceptColNames = new HashSet(exceptColumnNames.SplitCommaString(trimSpace: true));
Dictionary mapColumns = colNames.Where(c => !exceptColNames.Contains(c))
.Select((s) =>
{
if (hasMapping && s.Contains("="))
{
var names = s.SplitString("=", trimSpace: true);
return new { Key = names[0], Value = names[1] };
}
return new { Key = s, Value = s };
}).ToDictionary(k => k.Key, v => v.Value);
return mapColumns;
}
///
/// Gets the matched properties list.
///
///
/// The source.
/// The colum names filter (can be use = for mapping; ex: ColumnName = PropertyName).
/// The except column names.
/// The ignore prefix.
/// IDictionary<System.String, PropertyDescriptor>.
internal static IDictionary GetMatchedPropertiesList(this DataTable source, string columnNames = "", string exceptColumnNames = "", string ignorePrefix = "")
{
if (source == null)
{
return new Dictionary();
}
Type DataRowType = typeof(T);
bool mapAllColumns = columnNames.Contains("*") || string.IsNullOrWhiteSpace(columnNames);
bool hasIgnorePrefix = !string.IsNullOrWhiteSpace(ignorePrefix);
string[] ignorePrefixes = ignorePrefix.SplitByCommaOrSemiColon();
bool hasMapping = columnNames.Contains("=");
bool hasExceptColumn = !string.IsNullOrWhiteSpace(exceptColumnNames);
string[] exceptColNames = exceptColumnNames.SplitCommaString(trimSpace: true);
Dictionary allProperties = TypeDescriptor.GetProperties(DataRowType).Cast().ToDictionary(p =>
{
if (hasIgnorePrefix)
{
if (ignorePrefixes.Length > 1)
{
foreach (var prefix in ignorePrefixes)
{
if (prefix.StartsWith(prefix))
{
return p.Name.Substring(prefix.Length);
}
}
}
else if (p.Name.StartsWith(ignorePrefix))
{
return p.Name.Substring(ignorePrefix.Length);
}
}
return p.Name;
});
Dictionary colNames = columnNames.SplitCommaString(trimSpace: true)
.Where(c => !mapAllColumns || !c.Contains("*"))
.Select((s) =>
{
if (hasMapping && s.Contains("="))
{
var names = s.SplitString("=", trimSpace: true);
return new { Key = names[0], Value = names[1] };
}
return new { Key = s, Value = s };
}).ToDictionary(k => k.Key, v => v.Value);
IDictionary mapProperties = source.Columns.Cast()
.Select(c => new { c.ColumnName, PropertyName = colNames.ContainsKey(c.ColumnName) ? colNames[c.ColumnName] : c.ColumnName })
.Where(c => (mapAllColumns || colNames.ContainsKey(c.ColumnName))
&& allProperties.ContainsKey(c.PropertyName)
&& (!hasExceptColumn || Array.IndexOf(exceptColNames, c.ColumnName) == -1)
)
.ToDictionary(c => c.ColumnName, c => allProperties[c.PropertyName]);
return mapProperties;
}
///
/// Imports from model list.
///
///
/// The source.
/// The list.
/// The colum names filter (can be use = for mapping; ex: ColumnName = PropertyName).
/// The except column names.
/// The ignore prefix.
public static void ImportFromModel(this DataTable source, IList list, string columnNames = "", string exceptColumnNames = "", string ignorePrefix = "")
{
Type DataRowType = typeof(T);
IDictionary updateProperties = source.GetMatchedPropertiesList(columnNames, exceptColumnNames, ignorePrefix);
foreach (T item in list)
{
var newRow = source.NewRow();
newRow.UpdateFromModel(item, updateProperties);
source.Rows.Add(newRow);
}
}
///
/// Convert to Model List.
///
///
/// The source.
/// The colum names filter (can be use = for mapping; ex: ColumnName = PropertyName).
/// The except column names.
/// The model status field has receive status of source (field type must be DataRowState).
/// The ignore prefix.
/// The method.
/// IList<T>.
public static IList ConvertToModel(this DataTable source, string columnNames = "", string exceptColumnNames = "", string modelStatusField = "", string ignorePrefix = "", Action method = null)
{
Type DataRowType = typeof(T);
IDictionary updateProperties = source.GetMatchedPropertiesList(columnNames, exceptColumnNames, ignorePrefix);
IList list = new List();
if (source != null)
{
foreach (DataRow DataRow in source.Rows)
{
list.Add(DataRow.ConvertToModel(updateProperties, modelStatusField, method: method));
}
}
return list;
}
///
/// Updates from DataRow.
///
/// The source.
/// The value.
/// The colum names filter (can be use = for mapping; ex: ColumnName = PropertyName).
/// The except column names.
/// The key fields. (if not include key fields, auto use keys value to fields)
///
public static bool UpdateFrom(this DataTable source, DataRow value, string columnNames = "", string exceptColumnNames = "", string keyFields = "")
{
string keysColumns = string.Empty;
List columnList = new List();
List