|
|
@ -4,8 +4,6 @@ using System.Data; |
|
|
|
using System.Reflection; |
|
|
|
using System.Text; |
|
|
|
|
|
|
|
using static Apewer.NumberUtility; |
|
|
|
|
|
|
|
namespace Apewer.Source |
|
|
|
{ |
|
|
|
|
|
|
@ -13,7 +11,7 @@ namespace Apewer.Source |
|
|
|
public static class SourceUtility |
|
|
|
{ |
|
|
|
|
|
|
|
#region IQuery -> IRecord
|
|
|
|
#region ORM
|
|
|
|
|
|
|
|
/// <summary>读取所有行,生成列表。</summary>
|
|
|
|
public static T[] Fill<T>(this IQuery query) where T : class, new() |
|
|
@ -35,41 +33,19 @@ namespace Apewer.Source |
|
|
|
return Fill(query.Table, model); |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>获取指定列的所有值,无效值不加入结果。</summary>
|
|
|
|
public static T[] Column<T>(this IQuery query, Func<int, T> filler) |
|
|
|
{ |
|
|
|
if (query == null || filler == null) return new T[0]; |
|
|
|
|
|
|
|
var rows = query.Rows; |
|
|
|
var output = new T[rows]; |
|
|
|
var added = 0; |
|
|
|
for (int r = 0; r < rows; r++) |
|
|
|
{ |
|
|
|
var value = filler(r); |
|
|
|
if (value == null) continue; |
|
|
|
if (value is string str) |
|
|
|
{ |
|
|
|
if (str == "") continue; |
|
|
|
} |
|
|
|
output[added] = value; |
|
|
|
added++; |
|
|
|
} |
|
|
|
|
|
|
|
if (added < 1) return new T[0]; |
|
|
|
if (added == rows) return output; |
|
|
|
var output2 = new T[added]; |
|
|
|
Array.Copy(output, output2, added); |
|
|
|
return output2; |
|
|
|
} |
|
|
|
/// <summary>将 Query 的行,填充到模型实体。</summary>
|
|
|
|
/// <remarks>填充失败时返回 NULL 值。</remarks>
|
|
|
|
/// <exception cref="Exception"></exception>
|
|
|
|
public static object FillRow(IQuery query, int rowIndex, Type model, TableStructure structure) => FillRow(query?.Table, rowIndex, model, structure); |
|
|
|
|
|
|
|
/// <summary>将 Query 的行,填充到模型实体。</summary>
|
|
|
|
/// <remarks>填充失败时返回 NULL 值。</remarks>
|
|
|
|
/// <exception cref="Exception"></exception>
|
|
|
|
public static object Row(IQuery query, int rowIndex, Type model, TableStructure structure) |
|
|
|
public static object FillRow(DataTable table, int rowIndex, Type model, TableStructure structure) |
|
|
|
{ |
|
|
|
// 检查参数。
|
|
|
|
if (query == null || model == null || structure == null) return null; |
|
|
|
if (rowIndex < 0 || rowIndex >= query.Rows) return null; |
|
|
|
if (table == null || model == null || structure == null) return null; |
|
|
|
if (rowIndex < 0 || rowIndex >= table.Rows.Count) return null; |
|
|
|
if (!RuntimeUtility.CanNew(model)) return null; |
|
|
|
|
|
|
|
// 变量别名。
|
|
|
@ -99,7 +75,9 @@ namespace Apewer.Source |
|
|
|
field = property.Name; |
|
|
|
} |
|
|
|
|
|
|
|
var value = query.Value(r, field); |
|
|
|
|
|
|
|
var value = table.Rows[r][field]; |
|
|
|
if (value != null && value.Equals(DBNull.Value)) value = null; |
|
|
|
var setted = Set(record, property, value); |
|
|
|
} |
|
|
|
return record; |
|
|
@ -122,33 +100,33 @@ namespace Apewer.Source |
|
|
|
else if (pt.Equals(typeof(string))) setter.Invoke(record, new object[] { value.ToString() }); |
|
|
|
|
|
|
|
else if (pt.Equals(typeof(DateTime))) setter.Invoke(record, new object[] { value }); |
|
|
|
else if (pt.Equals(typeof(bool))) setter.Invoke(record, new object[] { Boolean(value) }); |
|
|
|
else if (pt.Equals(typeof(byte))) setter.Invoke(record, new object[] { Byte(value) }); |
|
|
|
else if (pt.Equals(typeof(sbyte))) setter.Invoke(record, new object[] { SByte(value) }); |
|
|
|
else if (pt.Equals(typeof(short))) setter.Invoke(record, new object[] { Int16(value) }); |
|
|
|
else if (pt.Equals(typeof(ushort))) setter.Invoke(record, new object[] { UInt16(value) }); |
|
|
|
else if (pt.Equals(typeof(int))) setter.Invoke(record, new object[] { Int32(value) }); |
|
|
|
else if (pt.Equals(typeof(uint))) setter.Invoke(record, new object[] { UInt32(value) }); |
|
|
|
else if (pt.Equals(typeof(long))) setter.Invoke(record, new object[] { Int64(value) }); |
|
|
|
else if (pt.Equals(typeof(ulong))) setter.Invoke(record, new object[] { UInt64(value) }); |
|
|
|
else if (pt.Equals(typeof(float))) setter.Invoke(record, new object[] { Single(value) }); |
|
|
|
else if (pt.Equals(typeof(double))) setter.Invoke(record, new object[] { Double(value) }); |
|
|
|
else if (pt.Equals(typeof(decimal))) setter.Invoke(record, new object[] { Decimal(value) }); |
|
|
|
else if (pt.Equals(typeof(bool))) setter.Invoke(record, new object[] { NumberUtility.Boolean(value) }); |
|
|
|
else if (pt.Equals(typeof(byte))) setter.Invoke(record, new object[] { NumberUtility.Byte(value) }); |
|
|
|
else if (pt.Equals(typeof(sbyte))) setter.Invoke(record, new object[] { NumberUtility.SByte(value) }); |
|
|
|
else if (pt.Equals(typeof(short))) setter.Invoke(record, new object[] { NumberUtility.Int16(value) }); |
|
|
|
else if (pt.Equals(typeof(ushort))) setter.Invoke(record, new object[] { NumberUtility.UInt16(value) }); |
|
|
|
else if (pt.Equals(typeof(int))) setter.Invoke(record, new object[] { NumberUtility.Int32(value) }); |
|
|
|
else if (pt.Equals(typeof(uint))) setter.Invoke(record, new object[] { NumberUtility.UInt32(value) }); |
|
|
|
else if (pt.Equals(typeof(long))) setter.Invoke(record, new object[] { NumberUtility.Int64(value) }); |
|
|
|
else if (pt.Equals(typeof(ulong))) setter.Invoke(record, new object[] { NumberUtility.UInt64(value) }); |
|
|
|
else if (pt.Equals(typeof(float))) setter.Invoke(record, new object[] { NumberUtility.Single(value) }); |
|
|
|
else if (pt.Equals(typeof(double))) setter.Invoke(record, new object[] { NumberUtility.Double(value) }); |
|
|
|
else if (pt.Equals(typeof(decimal))) setter.Invoke(record, new object[] { NumberUtility.Decimal(value) }); |
|
|
|
|
|
|
|
#if !NET20
|
|
|
|
else if (pt.Equals(typeof(Nullable<DateTime>))) setter.Invoke(record, new object[] { new Nullable<DateTime>((DateTime)value) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<bool>))) setter.Invoke(record, new object[] { new Nullable<bool>(Boolean(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<byte>))) setter.Invoke(record, new object[] { new Nullable<byte>(Byte(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<sbyte>))) setter.Invoke(record, new object[] { new Nullable<sbyte>(SByte(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<short>))) setter.Invoke(record, new object[] { new Nullable<short>(Int16(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<ushort>))) setter.Invoke(record, new object[] { new Nullable<int>(UInt16(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<int>))) setter.Invoke(record, new object[] { new Nullable<int>(Int32(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<uint>))) setter.Invoke(record, new object[] { new Nullable<uint>(UInt32(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<long>))) setter.Invoke(record, new object[] { new Nullable<long>(Int64(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<ulong>))) setter.Invoke(record, new object[] { new Nullable<ulong>(UInt64(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<float>))) setter.Invoke(record, new object[] { new Nullable<float>(Single(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<double>))) setter.Invoke(record, new object[] { new Nullable<double>(Double(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<decimal>))) setter.Invoke(record, new object[] { new Nullable<decimal>(Decimal(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<bool>))) setter.Invoke(record, new object[] { new Nullable<bool>(NumberUtility.Boolean(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<byte>))) setter.Invoke(record, new object[] { new Nullable<byte>(NumberUtility.Byte(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<sbyte>))) setter.Invoke(record, new object[] { new Nullable<sbyte>(NumberUtility.SByte(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<short>))) setter.Invoke(record, new object[] { new Nullable<short>(NumberUtility.Int16(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<ushort>))) setter.Invoke(record, new object[] { new Nullable<int>(NumberUtility.UInt16(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<int>))) setter.Invoke(record, new object[] { new Nullable<int>(NumberUtility.Int32(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<uint>))) setter.Invoke(record, new object[] { new Nullable<uint>(NumberUtility.UInt32(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<long>))) setter.Invoke(record, new object[] { new Nullable<long>(NumberUtility.Int64(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<ulong>))) setter.Invoke(record, new object[] { new Nullable<ulong>(NumberUtility.UInt64(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<float>))) setter.Invoke(record, new object[] { new Nullable<float>(NumberUtility.Single(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<double>))) setter.Invoke(record, new object[] { new Nullable<double>(NumberUtility.Double(value)) }); |
|
|
|
else if (pt.Equals(typeof(Nullable<decimal>))) setter.Invoke(record, new object[] { new Nullable<decimal>(NumberUtility.Decimal(value)) }); |
|
|
|
#endif
|
|
|
|
|
|
|
|
else |
|
|
@ -163,6 +141,176 @@ namespace Apewer.Source |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>解析 DataTable,填充没行到到指定的类型中,形成数组。</summary>
|
|
|
|
/// <param name="table">将要读取的表。</param>
|
|
|
|
/// <param name="compatible">当类型不同时,尝试转换以兼容。</param>
|
|
|
|
/// <returns>由指定类型组成的数组。</returns>
|
|
|
|
/// <exception cref="ArgumentNullException"></exception>
|
|
|
|
/// <exception cref="ArgumentException"></exception>
|
|
|
|
public static T[] Fill<T>(this DataTable table, bool compatible = true) |
|
|
|
{ |
|
|
|
if (table == null) throw new ArgumentNullException(nameof(table), $"参数 {table} 无效。"); |
|
|
|
var objects = Fill(table, typeof(T), compatible); |
|
|
|
var count = objects.Length; |
|
|
|
var array = new T[count]; |
|
|
|
for (var i = 0; i < count; i++) array[i] = (T)objects[i]; |
|
|
|
return array; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>解析 DataTable,填充没行到到指定的类型中,形成数组。</summary>
|
|
|
|
/// <param name="table">将要读取的表。</param>
|
|
|
|
/// <param name="model">要填充的目标类型,必须是可实例化的引用类型。</param>
|
|
|
|
/// <param name="compatible">当类型不同时,尝试转换以兼容。</param>
|
|
|
|
/// <returns>由指定类型组成的数组。</returns>
|
|
|
|
/// <exception cref="ArgumentNullException"></exception>
|
|
|
|
/// <exception cref="ArgumentException"></exception>
|
|
|
|
public static object[] Fill(this DataTable table, Type model, bool compatible = true) |
|
|
|
{ |
|
|
|
if (table == null) throw new ArgumentNullException(nameof(table), $"参数 {table} 无效。"); |
|
|
|
if (model == null) throw new ArgumentNullException(nameof(model), $"参数 {model} 无效。"); |
|
|
|
|
|
|
|
// 检查模型是否允许填充。
|
|
|
|
var ts = TableStructure.Parse(model, true, true); |
|
|
|
if (ts == null) throw new ArgumentException($"无法填充到类型 {model.FullName} 中。"); |
|
|
|
|
|
|
|
// 检查行数。
|
|
|
|
var rows = table.Rows; |
|
|
|
var rowsCount = rows.Count; |
|
|
|
if (rowsCount < 1) return new object[0]; |
|
|
|
|
|
|
|
// 确定数组。
|
|
|
|
var array = new object[rowsCount]; |
|
|
|
for (var i = 0; i < rowsCount; i++) array[i] = Activator.CreateInstance(model, true); |
|
|
|
|
|
|
|
// 检查列数。
|
|
|
|
var columns = table.Columns; |
|
|
|
var columnsCount = columns.Count; |
|
|
|
if (columnsCount < 1) return array; |
|
|
|
|
|
|
|
// 解析表头,仅保留有名称的列。
|
|
|
|
var sc = 0; |
|
|
|
var sfs = new string[columnsCount]; |
|
|
|
var sts = new Type[columnsCount]; |
|
|
|
var sis = new int[columnsCount]; |
|
|
|
for (var i = 0; i < columnsCount; i++) |
|
|
|
{ |
|
|
|
var column = columns[i]; |
|
|
|
var key = column.ColumnName.Lower(); |
|
|
|
if (string.IsNullOrEmpty(key)) continue; |
|
|
|
if (sfs.Contains(key)) continue; |
|
|
|
sfs[sc] = key; |
|
|
|
sts[sc] = column.DataType; |
|
|
|
sis[sc] = i; |
|
|
|
sc++; |
|
|
|
} |
|
|
|
if (sc < 1) return array; |
|
|
|
|
|
|
|
// 解析模型列。
|
|
|
|
var cas = ts.Fillable; |
|
|
|
var dc = 0; |
|
|
|
var dfs = new string[cas.Length]; |
|
|
|
var dts = new ColumnAttribute[cas.Length]; |
|
|
|
for (var i = 0; i < cas.Length; i++) |
|
|
|
{ |
|
|
|
var ca = cas[i]; |
|
|
|
var key = ca.Field.Lower(); |
|
|
|
if (string.IsNullOrEmpty(key)) continue; |
|
|
|
if (dfs.Contains(key)) continue; |
|
|
|
dfs[dc] = key; |
|
|
|
dts[dc] = ca; |
|
|
|
dc++; |
|
|
|
} |
|
|
|
if (dc < 1) return array; |
|
|
|
|
|
|
|
// 遍历、填充。
|
|
|
|
for (var r = 0; r < rowsCount; r++) |
|
|
|
{ |
|
|
|
var record = array[r]; |
|
|
|
|
|
|
|
// 遍历 table 的列。
|
|
|
|
for (var s = 0; s < sc; s++) |
|
|
|
{ |
|
|
|
var sf = sfs[s]; |
|
|
|
|
|
|
|
// 遍历 model 的列。
|
|
|
|
for (var d = 0; d < dc; d++) |
|
|
|
{ |
|
|
|
var df = dfs[d]; |
|
|
|
if (df != sf) continue; |
|
|
|
|
|
|
|
// 取值、填充。
|
|
|
|
var value = rows[r][sis[s]]; |
|
|
|
Fill(record, dts[d], sts[s], value, compatible); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return array; |
|
|
|
} |
|
|
|
|
|
|
|
static bool Fill(object record, ColumnAttribute ca, Type st, object value, bool compatible) |
|
|
|
{ |
|
|
|
// 如果是 NULL 则忽略填充。
|
|
|
|
if (value.IsNull()) return false; |
|
|
|
|
|
|
|
// 获取属性的类型,必须与 table 中的类型相同。
|
|
|
|
var prop = ca.Property; |
|
|
|
if (prop.PropertyType == st) |
|
|
|
{ |
|
|
|
prop.SetValue(record, value, null); |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
// 类型不同且不需要兼容时,不填充。
|
|
|
|
if (!compatible) return false; |
|
|
|
|
|
|
|
// 根据属性类型设置值。
|
|
|
|
var pt = prop.PropertyType; |
|
|
|
if (pt.Equals(typeof(object))) prop.SetValue(record, value, null); |
|
|
|
else if (pt.Equals(typeof(byte[]))) prop.SetValue(record, (byte[])value, null); |
|
|
|
else if (pt.Equals(typeof(string))) prop.SetValue(record, value.ToString(), null); |
|
|
|
|
|
|
|
else if (pt.Equals(typeof(DateTime))) prop.SetValue(record, value, null); |
|
|
|
else if (pt.Equals(typeof(bool))) prop.SetValue(record, NumberUtility.Boolean(value), null); |
|
|
|
else if (pt.Equals(typeof(byte))) prop.SetValue(record, NumberUtility.Byte(value), null); |
|
|
|
else if (pt.Equals(typeof(sbyte))) prop.SetValue(record, NumberUtility.SByte(value), null); |
|
|
|
else if (pt.Equals(typeof(short))) prop.SetValue(record, NumberUtility.Int16(value), null); |
|
|
|
else if (pt.Equals(typeof(ushort))) prop.SetValue(record, NumberUtility.UInt16(value), null); |
|
|
|
else if (pt.Equals(typeof(int))) prop.SetValue(record, NumberUtility.Int32(value), null); |
|
|
|
else if (pt.Equals(typeof(uint))) prop.SetValue(record, NumberUtility.UInt32(value), null); |
|
|
|
else if (pt.Equals(typeof(long))) prop.SetValue(record, NumberUtility.Int64(value), null); |
|
|
|
else if (pt.Equals(typeof(ulong))) prop.SetValue(record, NumberUtility.UInt64(value), null); |
|
|
|
else if (pt.Equals(typeof(float))) prop.SetValue(record, NumberUtility.Single(value), null); |
|
|
|
else if (pt.Equals(typeof(double))) prop.SetValue(record, NumberUtility.Double(value), null); |
|
|
|
else if (pt.Equals(typeof(decimal))) prop.SetValue(record, NumberUtility.Decimal(value), null); |
|
|
|
|
|
|
|
else if (pt.Equals(typeof(Nullable<DateTime>))) prop.SetValue(record, new Nullable<DateTime>((DateTime)value), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<bool>))) prop.SetValue(record, new Nullable<bool>(NumberUtility.Boolean(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<byte>))) prop.SetValue(record, new Nullable<byte>(NumberUtility.Byte(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<sbyte>))) prop.SetValue(record, new Nullable<sbyte>(NumberUtility.SByte(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<short>))) prop.SetValue(record, new Nullable<short>(NumberUtility.Int16(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<ushort>))) prop.SetValue(record, new Nullable<int>(NumberUtility.UInt16(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<int>))) prop.SetValue(record, new Nullable<int>(NumberUtility.Int32(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<uint>))) prop.SetValue(record, new Nullable<uint>(NumberUtility.UInt32(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<long>))) prop.SetValue(record, new Nullable<long>(NumberUtility.Int64(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<ulong>))) prop.SetValue(record, new Nullable<ulong>(NumberUtility.UInt64(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<float>))) prop.SetValue(record, new Nullable<float>(NumberUtility.Single(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<double>))) prop.SetValue(record, new Nullable<double>(NumberUtility.Double(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<decimal>))) prop.SetValue(record, new Nullable<decimal>(NumberUtility.Decimal(value)), null); |
|
|
|
|
|
|
|
else |
|
|
|
{ |
|
|
|
try |
|
|
|
{ |
|
|
|
prop.SetValue(record, value, null); |
|
|
|
return true; |
|
|
|
} |
|
|
|
catch { } |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region Record
|
|
|
@ -493,177 +641,7 @@ namespace Apewer.Source |
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region DataTable
|
|
|
|
|
|
|
|
/// <summary>解析 DataTable,填充没行到到指定的类型中,形成数组。</summary>
|
|
|
|
/// <param name="table">将要读取的表。</param>
|
|
|
|
/// <param name="compatible">当类型不同时,尝试转换以兼容。</param>
|
|
|
|
/// <returns>由指定类型组成的数组。</returns>
|
|
|
|
/// <exception cref="ArgumentNullException"></exception>
|
|
|
|
/// <exception cref="ArgumentException"></exception>
|
|
|
|
public static T[] Fill<T>(this DataTable table, bool compatible = true) |
|
|
|
{ |
|
|
|
if (table == null) throw new ArgumentNullException(nameof(table), $"参数 {table} 无效。"); |
|
|
|
var objects = Fill(table, typeof(T), compatible); |
|
|
|
var count = objects.Length; |
|
|
|
var array = new T[count]; |
|
|
|
for (var i = 0; i < count; i++) array[i] = (T)objects[i]; |
|
|
|
return array; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>解析 DataTable,填充没行到到指定的类型中,形成数组。</summary>
|
|
|
|
/// <param name="table">将要读取的表。</param>
|
|
|
|
/// <param name="model">要填充的目标类型,必须是可实例化的引用类型。</param>
|
|
|
|
/// <param name="compatible">当类型不同时,尝试转换以兼容。</param>
|
|
|
|
/// <returns>由指定类型组成的数组。</returns>
|
|
|
|
/// <exception cref="ArgumentNullException"></exception>
|
|
|
|
/// <exception cref="ArgumentException"></exception>
|
|
|
|
public static object[] Fill(this DataTable table, Type model, bool compatible = true) |
|
|
|
{ |
|
|
|
if (table == null) throw new ArgumentNullException(nameof(table), $"参数 {table} 无效。"); |
|
|
|
if (model == null) throw new ArgumentNullException(nameof(model), $"参数 {model} 无效。"); |
|
|
|
|
|
|
|
// 检查模型是否允许填充。
|
|
|
|
var ts = TableStructure.Parse(model, true, true); |
|
|
|
if (ts == null) throw new ArgumentException($"无法填充到类型 {model.FullName} 中。"); |
|
|
|
|
|
|
|
// 检查行数。
|
|
|
|
var rows = table.Rows; |
|
|
|
var rowsCount = rows.Count; |
|
|
|
if (rowsCount < 1) return new object[0]; |
|
|
|
|
|
|
|
// 确定数组。
|
|
|
|
var array = new object[rowsCount]; |
|
|
|
for (var i = 0; i < rowsCount; i++) array[i] = Activator.CreateInstance(model, true); |
|
|
|
|
|
|
|
// 检查列数。
|
|
|
|
var columns = table.Columns; |
|
|
|
var columnsCount = columns.Count; |
|
|
|
if (columnsCount < 1) return array; |
|
|
|
|
|
|
|
// 解析表头,仅保留有名称的列。
|
|
|
|
var sc = 0; |
|
|
|
var sfs = new string[columnsCount]; |
|
|
|
var sts = new Type[columnsCount]; |
|
|
|
var sis = new int[columnsCount]; |
|
|
|
for (var i = 0; i < columnsCount; i++) |
|
|
|
{ |
|
|
|
var column = columns[i]; |
|
|
|
var key = column.ColumnName.Lower(); |
|
|
|
if (string.IsNullOrEmpty(key)) continue; |
|
|
|
if (sfs.Contains(key)) continue; |
|
|
|
sfs[sc] = key; |
|
|
|
sts[sc] = column.DataType; |
|
|
|
sis[sc] = i; |
|
|
|
sc++; |
|
|
|
} |
|
|
|
if (sc < 1) return array; |
|
|
|
|
|
|
|
// 解析模型列。
|
|
|
|
var cas = ts.Fillable; |
|
|
|
var dc = 0; |
|
|
|
var dfs = new string[cas.Length]; |
|
|
|
var dts = new ColumnAttribute[cas.Length]; |
|
|
|
for (var i = 0; i < cas.Length; i++) |
|
|
|
{ |
|
|
|
var ca = cas[i]; |
|
|
|
var key = ca.Field.Lower(); |
|
|
|
if (string.IsNullOrEmpty(key)) continue; |
|
|
|
if (dfs.Contains(key)) continue; |
|
|
|
dfs[dc] = key; |
|
|
|
dts[dc] = ca; |
|
|
|
dc++; |
|
|
|
} |
|
|
|
if (dc < 1) return array; |
|
|
|
|
|
|
|
// 遍历、填充。
|
|
|
|
for (var r = 0; r < rowsCount; r++) |
|
|
|
{ |
|
|
|
var record = array[r]; |
|
|
|
|
|
|
|
// 遍历 table 的列。
|
|
|
|
for (var s = 0; s < sc; s++) |
|
|
|
{ |
|
|
|
var sf = sfs[s]; |
|
|
|
|
|
|
|
// 遍历 model 的列。
|
|
|
|
for (var d = 0; d < dc; d++) |
|
|
|
{ |
|
|
|
var df = dfs[d]; |
|
|
|
if (df != sf) continue; |
|
|
|
|
|
|
|
// 取值、填充。
|
|
|
|
var value = rows[r][sis[s]]; |
|
|
|
Fill(record, dts[d], sts[s], value, compatible); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
return array; |
|
|
|
} |
|
|
|
|
|
|
|
static bool Fill(object record, ColumnAttribute ca, Type st, object value, bool compatible) |
|
|
|
{ |
|
|
|
// 如果是 NULL 则忽略填充。
|
|
|
|
if (value.IsNull()) return false; |
|
|
|
|
|
|
|
// 获取属性的类型,必须与 table 中的类型相同。
|
|
|
|
var prop = ca.Property; |
|
|
|
if (prop.PropertyType == st) |
|
|
|
{ |
|
|
|
prop.SetValue(record, value, null); |
|
|
|
return true; |
|
|
|
} |
|
|
|
|
|
|
|
// 类型不同且不需要兼容时,不填充。
|
|
|
|
if (!compatible) return false; |
|
|
|
|
|
|
|
// 根据属性类型设置值。
|
|
|
|
var pt = prop.PropertyType; |
|
|
|
if (pt.Equals(typeof(object))) prop.SetValue(record, value, null); |
|
|
|
else if (pt.Equals(typeof(byte[]))) prop.SetValue(record, (byte[])value, null); |
|
|
|
else if (pt.Equals(typeof(string))) prop.SetValue(record, value.ToString(), null); |
|
|
|
|
|
|
|
else if (pt.Equals(typeof(DateTime))) prop.SetValue(record, value, null); |
|
|
|
else if (pt.Equals(typeof(bool))) prop.SetValue(record, Boolean(value), null); |
|
|
|
else if (pt.Equals(typeof(byte))) prop.SetValue(record, Byte(value), null); |
|
|
|
else if (pt.Equals(typeof(sbyte))) prop.SetValue(record, SByte(value), null); |
|
|
|
else if (pt.Equals(typeof(short))) prop.SetValue(record, Int16(value), null); |
|
|
|
else if (pt.Equals(typeof(ushort))) prop.SetValue(record, UInt16(value), null); |
|
|
|
else if (pt.Equals(typeof(int))) prop.SetValue(record, Int32(value), null); |
|
|
|
else if (pt.Equals(typeof(uint))) prop.SetValue(record, UInt32(value), null); |
|
|
|
else if (pt.Equals(typeof(long))) prop.SetValue(record, Int64(value), null); |
|
|
|
else if (pt.Equals(typeof(ulong))) prop.SetValue(record, UInt64(value), null); |
|
|
|
else if (pt.Equals(typeof(float))) prop.SetValue(record, Single(value), null); |
|
|
|
else if (pt.Equals(typeof(double))) prop.SetValue(record, Double(value), null); |
|
|
|
else if (pt.Equals(typeof(decimal))) prop.SetValue(record, Decimal(value), null); |
|
|
|
|
|
|
|
else if (pt.Equals(typeof(Nullable<DateTime>))) prop.SetValue(record, new Nullable<DateTime>((DateTime)value), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<bool>))) prop.SetValue(record, new Nullable<bool>(Boolean(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<byte>))) prop.SetValue(record, new Nullable<byte>(Byte(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<sbyte>))) prop.SetValue(record, new Nullable<sbyte>(SByte(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<short>))) prop.SetValue(record, new Nullable<short>(Int16(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<ushort>))) prop.SetValue(record, new Nullable<int>(UInt16(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<int>))) prop.SetValue(record, new Nullable<int>(Int32(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<uint>))) prop.SetValue(record, new Nullable<uint>(UInt32(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<long>))) prop.SetValue(record, new Nullable<long>(Int64(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<ulong>))) prop.SetValue(record, new Nullable<ulong>(UInt64(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<float>))) prop.SetValue(record, new Nullable<float>(Single(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<double>))) prop.SetValue(record, new Nullable<double>(Double(value)), null); |
|
|
|
else if (pt.Equals(typeof(Nullable<decimal>))) prop.SetValue(record, new Nullable<decimal>(Decimal(value)), null); |
|
|
|
|
|
|
|
else |
|
|
|
{ |
|
|
|
try |
|
|
|
{ |
|
|
|
prop.SetValue(record, value, null); |
|
|
|
return true; |
|
|
|
} |
|
|
|
catch { } |
|
|
|
} |
|
|
|
return false; |
|
|
|
} |
|
|
|
#region 数据模型 -> DataTable
|
|
|
|
|
|
|
|
/// <summary>将多个实体元素转换为 DataTable。</summary>
|
|
|
|
/// <typeparam name="T">实体元素的类型。</typeparam>
|
|
|
@ -748,9 +726,13 @@ namespace Apewer.Source |
|
|
|
return table; |
|
|
|
} |
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region DataTable 序列化
|
|
|
|
|
|
|
|
/// <summary>转换 <see cref="System.Data.DataTable"/> 到 <see cref="ObjectSet{T}"/> 数组,每行记录为一个 ObjectSet 对象。</summary>
|
|
|
|
/// <returns>当参数 table 无效时返回 0 长度的 <see cref="ObjectSet{T}"/> 数组。</returns>
|
|
|
|
internal static ObjectSet[] ObjectSet(this DataTable table) |
|
|
|
public static ObjectSet[] ObjectSet(this DataTable table) |
|
|
|
{ |
|
|
|
if (table == null) return new ObjectSet[0]; |
|
|
|
|
|
|
@ -780,7 +762,104 @@ namespace Apewer.Source |
|
|
|
return oss; |
|
|
|
} |
|
|
|
|
|
|
|
internal static string Csv(DataTable table, bool withHead) |
|
|
|
/// <summary>转换为 Json 对象。</summary>
|
|
|
|
public static Json ToJson(this DataTable table, Func<DateTime, string> dateTimeFormatter = null) |
|
|
|
{ |
|
|
|
if (table == null) return null; |
|
|
|
|
|
|
|
var columns = ToJson(table.Columns); |
|
|
|
var rows = ToJson(table.Rows); |
|
|
|
|
|
|
|
var jsonObject = Json.NewObject(); |
|
|
|
jsonObject.SetProperty("columns", columns); |
|
|
|
jsonObject.SetProperty("rows", rows); |
|
|
|
return jsonObject; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>转换为 Json 对象。</summary>
|
|
|
|
public static Json ToJson(this DataColumnCollection columns) |
|
|
|
{ |
|
|
|
if (columns == null) return null; |
|
|
|
|
|
|
|
var json = Json.NewArray(); |
|
|
|
var count = columns.Count; |
|
|
|
for (var c = 0; c < count; c++) |
|
|
|
{ |
|
|
|
var dc = columns[c]; |
|
|
|
var column = Json.NewObject(); |
|
|
|
column.SetProperty("name", dc.ColumnName); |
|
|
|
column.SetProperty("type", dc.DataType.FullName); |
|
|
|
json.AddItem(column); |
|
|
|
} |
|
|
|
return json; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>转换为 Json 对象。</summary>
|
|
|
|
public static Json ToJson(this DataRowCollection rows, Func<DateTime, object> dateTimeFormatter = null) |
|
|
|
{ |
|
|
|
if (rows == null) return null; |
|
|
|
|
|
|
|
var json = Json.NewArray(); |
|
|
|
var count = rows.Count; |
|
|
|
for (var r = 0; r < count; r++) |
|
|
|
{ |
|
|
|
json.AddItem(ToJson(rows[r], dateTimeFormatter)); |
|
|
|
} |
|
|
|
return json; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>转换为 Json 对象。</summary>
|
|
|
|
public static Json ToJson(this DataRow row, Func<DateTime, object> dateTimeFormatter = null) |
|
|
|
{ |
|
|
|
if (row == null) return null; |
|
|
|
var cells = row.ItemArray; |
|
|
|
var count = cells.Length; |
|
|
|
|
|
|
|
var json = Json.NewArray(); |
|
|
|
for (var c = 0; c < count; c++) |
|
|
|
{ |
|
|
|
var value = cells[c]; |
|
|
|
if (value == null || value.Equals(DBNull.Value)) |
|
|
|
{ |
|
|
|
json.AddItem(); |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
if (value is DateTime vDateTime) |
|
|
|
{ |
|
|
|
if (dateTimeFormatter == null) |
|
|
|
{ |
|
|
|
json.AddItem(Json.SerializeDateTime(vDateTime)); |
|
|
|
continue; |
|
|
|
} |
|
|
|
else |
|
|
|
{ |
|
|
|
value = dateTimeFormatter.Invoke(vDateTime); |
|
|
|
if (value == null || value.Equals(DBNull.Value)) |
|
|
|
{ |
|
|
|
json.AddItem(); |
|
|
|
continue; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (value is string @string) json.AddItem(@string); |
|
|
|
else if (value is byte @byte) json.AddItem(@byte); |
|
|
|
else if (value is short @short) json.AddItem(@short); |
|
|
|
else if (value is int @int) json.AddItem(@int); |
|
|
|
else if (value is long @long) json.AddItem(@long); |
|
|
|
else if (value is float @float) json.AddItem(@float); |
|
|
|
else if (value is double @double) json.AddItem(@double); |
|
|
|
else if (value is decimal @decimal) json.AddItem(@decimal); |
|
|
|
else if (value is bool @bool) json.AddItem(@bool); |
|
|
|
else if (value is byte[] bytes) json.AddItem(bytes.Base64()); |
|
|
|
else json.AddItem(TextUtility.Text(value)); |
|
|
|
} |
|
|
|
return json; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>转换 <see cref="DataTable"/> 为 CSV 文本,不存在表时返回 NULL 值。可指定是否包含表头。</summary>
|
|
|
|
public static string Csv(DataTable table, bool withHead = false) |
|
|
|
{ |
|
|
|
if (table == null) return null; |
|
|
|
|
|
|
@ -864,6 +943,123 @@ namespace Apewer.Source |
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region DataTable 快捷操作
|
|
|
|
|
|
|
|
/// <summary>获取默认表中指定单元格的内容。</summary>
|
|
|
|
/// <param name="table">数据表。</param>
|
|
|
|
/// <param name="rowIndex">行索引,从 0 开始。</param>
|
|
|
|
/// <param name="columnIndex">列索引,从 0 开始。</param>
|
|
|
|
public static object Value(this DataTable table, int rowIndex, int columnIndex) |
|
|
|
{ |
|
|
|
if (table != null) |
|
|
|
{ |
|
|
|
if (rowIndex >= 0 && rowIndex < table.Rows.Count) |
|
|
|
{ |
|
|
|
if (columnIndex >= 0 && columnIndex < table.Columns.Count) |
|
|
|
{ |
|
|
|
var value = table.Rows[rowIndex][columnIndex]; |
|
|
|
if (value == null || value.Equals(DBNull.Value)) return null; |
|
|
|
return value; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>获取默认表中指定单元的内容。</summary>
|
|
|
|
/// <param name="table">数据表。</param>
|
|
|
|
/// <param name="rowIndex">行索引,从 0 开始。</param>
|
|
|
|
/// <param name="columnName">列名称/字段名称,此名称不区分大小写。</param>
|
|
|
|
public static object Value(this DataTable table, int rowIndex, string columnName) |
|
|
|
{ |
|
|
|
if (table != null && !string.IsNullOrEmpty(columnName)) |
|
|
|
{ |
|
|
|
if ((rowIndex < table.Rows.Count) && (rowIndex >= 0)) |
|
|
|
{ |
|
|
|
try |
|
|
|
{ |
|
|
|
var value = table.Rows[rowIndex][columnName]; |
|
|
|
if (value == null || value.Equals(DBNull.Value)) return null; |
|
|
|
return value; |
|
|
|
} |
|
|
|
catch { } |
|
|
|
} |
|
|
|
} |
|
|
|
return null; |
|
|
|
} |
|
|
|
|
|
|
|
/// <summary>获取默认表中指定单元格的内容。从第 0 行第 0 列开始。</summary>
|
|
|
|
public static Class<DateTime> DateTime(this DataTable table, int row = 0, int column = 0) => table == null ? null : ClockUtility.DateTime(table.Value(row, column)); |
|
|
|
|
|
|
|
/// <summary>获取默认表中指定单元格的内容。从第 0 行开始。</summary>
|
|
|
|
public static Class<DateTime> DateTime(this DataTable table, int row, string column) => table == null ? null : ClockUtility.DateTime(table.Value(row, column)); |
|
|
|
|
|
|
|
/// <summary>获取默认表中指定单元格的内容。从第 0 行第 0 列开始。</summary>
|
|
|
|
public static Int32 Int32(this DataTable table, int row = 0, int column = 0) => table == null ? 0 : NumberUtility.Int32(table.Value(row, column)); |
|
|
|
|
|
|
|
/// <summary>获取默认表中指定单元格的内容。从第 0 行开始。</summary>
|
|
|
|
public static Int32 Int32(this DataTable table, int row, string column) => table == null ? 0 : NumberUtility.Int32(table.Value(row, column)); |
|
|
|
|
|
|
|
/// <summary>获取默认表中指定单元格的内容。从第 0 行第 0 列开始。</summary>
|
|
|
|
public static Int64 Int64(this DataTable table, int row = 0, int column = 0) => table == null ? 0L : NumberUtility.Int64(table.Value(row, column)); |
|
|
|
|
|
|
|
/// <summary>获取默认表中指定单元格的内容。从第 0 行开始。</summary>
|
|
|
|
public static Int64 Int64(this DataTable table, int row, string column) => table == null ? 0L : NumberUtility.Int64(table.Value(row, column)); |
|
|
|
|
|
|
|
/// <summary>获取默认表中指定单元格的内容。从第 0 行第 0 列开始。</summary>
|
|
|
|
public static Decimal Decimal(this DataTable table, int row = 0, int column = 0) => table == null ? 0M : NumberUtility.Decimal(table.Value(row, column)); |
|
|
|
|
|
|
|
/// <summary>获取默认表中指定单元格的内容。从第 0 行开始。</summary>
|
|
|
|
public static Decimal Decimal(this DataTable table, int row, string column) => table == null ? 0M : NumberUtility.Decimal(table.Value(row, column)); |
|
|
|
|
|
|
|
/// <summary>获取默认表中指定单元格的内容。从第 0 行第 0 列开始。</summary>>
|
|
|
|
public static Double Double(this DataTable table, int row = 0, int column = 0) => table == null ? 0D : NumberUtility.Double(table.Value(row, column)); |
|
|
|
|
|
|
|
/// <summary>获取默认表中指定单元格的内容。从第 0 行开始。</summary>>
|
|
|
|
public static Double Double(this DataTable table, int row, string column) => table == null ? 0D : NumberUtility.Double(table.Value(row, column)); |
|
|
|
|
|
|
|
/// <summary>获取默认表中指定单元格的内容。从第 0 行第 0 列开始。</summary>
|
|
|
|
public static string Text(this DataTable table, int row = 0, int column = 0) => table == null ? null : TextUtility.Text(table.Value(row, column)); |
|
|
|
|
|
|
|
/// <summary>获取默认表中指定单元格的内容。从第 0 行开始。</summary>
|
|
|
|
public static string Text(this DataTable table, int row, string column) => table == null ? null : TextUtility.Text(table.Value(row, column)); |
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region Dynamic
|
|
|
|
|
|
|
|
#if NET40_OR_GREATER
|
|
|
|
|
|
|
|
/// <summary>转换 ObjectSet 数组为 dynamic 数组。</summary>
|
|
|
|
public static dynamic[] Dynamic(this ObjectSet[] oss) |
|
|
|
{ |
|
|
|
if (oss == null) return new dynamic[0]; |
|
|
|
|
|
|
|
var eos = oss.Expando(); |
|
|
|
var ds = new dynamic[eos.Length]; |
|
|
|
eos.CopyTo(ds, 0); |
|
|
|
return ds; |
|
|
|
} |
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
#region 表达式计算
|
|
|
|
|
|
|
|
/// <summary>计算文本表达式。</summary>
|
|
|
|
public static object Compute(string expression) |
|
|
|
{ |
|
|
|
using (var table = new DataTable()) |
|
|
|
{ |
|
|
|
var result = table.Compute(expression, null); |
|
|
|
if (result.IsNull()) return null; |
|
|
|
return result; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
#endregion
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|