You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
382 lines
14 KiB
382 lines
14 KiB
using Apewer.Internals;
|
|
using Newtonsoft.Json.Linq;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Data;
|
|
|
|
using static Apewer.TextUtility;
|
|
|
|
namespace Apewer.Source
|
|
{
|
|
|
|
/// <summary>System.Data.DataTable 装箱查询。</summary>
|
|
public class Query : IQuery, IDisposable, IToJson
|
|
{
|
|
|
|
private bool _disposed = false;
|
|
private bool _success = false;
|
|
private string _message = null;
|
|
private DataTable _table = null;
|
|
private DataTable[] _tables = null;
|
|
|
|
/// <summary>创建实例,默认状态为失败。</summary>
|
|
public Query(bool success = false, string message = null)
|
|
{
|
|
_success = false;
|
|
_message = message;
|
|
}
|
|
|
|
/// <summary>创建实例,Exception 为 NULL 时成功,非 NULL 时失败。</summary>
|
|
public Query(Exception exception)
|
|
{
|
|
_success = exception == null;
|
|
_message = RuntimeUtility.Message(exception);
|
|
}
|
|
|
|
/// <summary>创建实例,包装一个 DataTable 对象,数据表为 NULL 时失败,非 NULL 时成功。</summary>
|
|
public Query(DataTable table)
|
|
{
|
|
_table = table;
|
|
_success = table != null;
|
|
_message = table == null ? "未获取有效的数据表。" : null;
|
|
}
|
|
|
|
/// <summary>创建实例,包装一个 DataTable 对象。</summary>
|
|
public Query(DataTable table, bool success, string message = null)
|
|
{
|
|
_table = table;
|
|
_success = success;
|
|
_message = message;
|
|
}
|
|
|
|
/// <summary>创建实例,包装多个 DataTable 对象。</summary>
|
|
public Query(DataTable[] tables, bool success = true, string message = null)
|
|
{
|
|
_tables = tables;
|
|
_success = success;
|
|
_message = message;
|
|
if (tables != null && tables.Length > 0) _table = tables[0];
|
|
}
|
|
|
|
#region Property
|
|
|
|
/// <summary>语句执行成功。</summary>
|
|
public bool Success { get => _success; }
|
|
|
|
/// <summary>消息。</summary>
|
|
public string Message { get => _message; }
|
|
|
|
/// <summary>所有结果表。</summary>
|
|
public DataTable[] Tables { get => _tables; }
|
|
|
|
/// <summary>获取默认结果表。如果设置默认结果表,会丢失设置前的所有结果表。</summary>
|
|
public DataTable Table { get => _table; }
|
|
|
|
/// <summary>默认表中的数据总行数。</summary>
|
|
public int Rows { get => _table == null ? 0 : _table.Rows.Count; }
|
|
|
|
/// <summary>默认表中的数据总列数。</summary>
|
|
public int Columns { get => _table == null ? 0 : _table.Columns.Count; }
|
|
|
|
#endregion
|
|
|
|
#region Value
|
|
|
|
/// <summary>获取默认表中第 0 行、第 0 列的单元格内容。</summary>
|
|
public object Value()
|
|
{
|
|
if (_disposed) return null;
|
|
return Value(0, 0);
|
|
}
|
|
|
|
/// <summary>获取默认表中指定行中第 0 列的内容。</summary>
|
|
/// <param name="rowIndex">行索引,从 0 开始。</param>
|
|
public object Value(int rowIndex)
|
|
{
|
|
if (_disposed) return null;
|
|
return Value(rowIndex, 0);
|
|
}
|
|
|
|
/// <summary>获取默认表中第 0 行指定列的内容。</summary>
|
|
/// <param name="columnName">列名称。</param>
|
|
public object Value(string columnName)
|
|
{
|
|
if (_disposed) return null;
|
|
return Value(0, columnName);
|
|
}
|
|
|
|
/// <summary>获取默认表中指定单元格的内容。</summary>
|
|
/// <param name="rowIndex">行索引,从 0 开始。</param>
|
|
/// <param name="columnIndex">列索引,从 0 开始。</param>
|
|
public object Value(int rowIndex, int columnIndex)
|
|
{
|
|
if (_disposed) return null;
|
|
if (_table != null)
|
|
{
|
|
if (rowIndex >= 0 && rowIndex < _table.Rows.Count)
|
|
{
|
|
if (columnIndex >= 0 && columnIndex < _table.Columns.Count)
|
|
{
|
|
return _table.Rows[rowIndex][columnIndex];
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>获取默认表中指定单元的内容。</summary>
|
|
/// <param name="rowIndex">行索引,从 0 开始。</param>
|
|
/// <param name="columnName">列名称。</param>
|
|
public object Value(int rowIndex, string columnName)
|
|
{
|
|
if (_disposed) return null;
|
|
if ((Table != null) && !string.IsNullOrEmpty(columnName))
|
|
{
|
|
if ((rowIndex < Table.Rows.Count) && (rowIndex >= 0))
|
|
{
|
|
try { return Table.Rows[rowIndex][columnName]; }
|
|
catch { }
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>搜索默认表。</summary>
|
|
/// <param name="conditionColumn">搜索条件:列名。</param>
|
|
/// <param name="conditionValue">搜索条件:列值。</param>
|
|
/// <param name="resultColumn">搜索结果。</param>
|
|
public object Value(string conditionColumn, string conditionValue, string resultColumn)
|
|
{
|
|
if (_disposed) return null;
|
|
if ((Table != null) && (!string.IsNullOrEmpty(conditionColumn)) && (conditionValue != null) && (!string.IsNullOrEmpty(resultColumn)))
|
|
{
|
|
for (int i = 0; i < Table.Rows.Count; i++)
|
|
{
|
|
try
|
|
{
|
|
if (Table.Rows[i][conditionColumn].ToString() == conditionValue) return Table.Rows[i][resultColumn];
|
|
}
|
|
catch { }
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
/// <summary>搜索默认表。</summary>
|
|
/// <param name="conditionColumn">搜索条件:列名。</param>
|
|
/// <param name="conditionValue">搜索条件:列值。</param>
|
|
/// <param name="resultColumn">搜索结果的列名。</param>
|
|
public object Value(int conditionColumn, string conditionValue, int resultColumn)
|
|
{
|
|
if (_disposed) return null;
|
|
if ((Table != null) && (conditionColumn >= 0) && (conditionValue != null) && (resultColumn >= 0))
|
|
{
|
|
if ((conditionColumn < Table.Columns.Count) && (resultColumn < Table.Columns.Count))
|
|
{
|
|
for (int i = 0; i < Table.Rows.Count; i++)
|
|
{
|
|
try
|
|
{
|
|
if (Table.Rows[i][conditionColumn].ToString() == conditionValue) return Table.Rows[i][resultColumn];
|
|
}
|
|
catch { }
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Method
|
|
|
|
/// <summary>搜索默认表。</summary>
|
|
/// <param name="conditionColumn">搜索条件:列名。</param>
|
|
/// <param name="conditionValue">搜索条件:列值。</param>
|
|
/// <param name="resultColumn">搜索结果。</param>
|
|
public string Text(int conditionColumn, string conditionValue, int resultColumn)
|
|
{
|
|
var value = Value(conditionColumn, conditionValue, resultColumn);
|
|
return Text(value);
|
|
}
|
|
|
|
/// <summary>释放系统资源。</summary>
|
|
public virtual void Dispose()
|
|
{
|
|
if (_disposed) return;
|
|
if (_tables != null)
|
|
{
|
|
foreach (var table in _tables) RuntimeUtility.Dispose(table);
|
|
_tables = null;
|
|
}
|
|
RuntimeUtility.Dispose(_table);
|
|
_table = null;
|
|
_tables = null;
|
|
_disposed = true;
|
|
// GC.SuppressFinalize(this);
|
|
}
|
|
|
|
/// <summary>当不指定格式化程序时,自动根据类型选择预置的格式化程序。</summary>
|
|
private static Func<object, T> GetValueFormatter<T>()
|
|
{
|
|
var type = typeof(T);
|
|
if (type.Equals(typeof(string))) return TextFormatter<T>;
|
|
else return ForceFormatter<T>;
|
|
}
|
|
|
|
/// <summary>获取指定列的所有值,无效值不加入结果。</summary>
|
|
public T[] ReadColumn<T>(int column = 0, Func<object, T> formatter = null) => SourceUtility.Column(this, (r) => (formatter ?? GetValueFormatter<T>()).Invoke(Value(r, column)));
|
|
|
|
/// <summary>获取指定列的所有值,无效值不加入结果。</summary>
|
|
/// <exception cref="ArgumentNullException"></exception>
|
|
public T[] ReadColumn<T>(string column, Func<object, T> formatter = null) => SourceUtility.Column(this, (r) => (formatter ?? GetValueFormatter<T>()).Invoke(Value(r, column)));
|
|
|
|
/// <summary>获取指定列的所有值,无效值不加入结果。</summary>
|
|
public string[] ReadColumn(int column = 0) => SourceUtility.Column(this, (r) => this.Text(r, column));
|
|
|
|
/// <summary>获取指定列的所有值,无效值不加入结果。</summary>
|
|
/// <exception cref="ArgumentNullException"></exception>
|
|
public string[] ReadColumn(string column) => SourceUtility.Column(this, (r) => this.Text(r, column));
|
|
|
|
#endregion
|
|
|
|
#region 模型化、IToJson
|
|
|
|
/// <summary>转换为 Json 对象。</summary>
|
|
public Json ToJson()
|
|
{
|
|
var columns = Json.NewArray();
|
|
var rows = Json.NewArray();
|
|
|
|
var table = _table;
|
|
if (!_disposed && table != null)
|
|
{
|
|
var columnsCount = table.Columns.Count;
|
|
for (var c = 0; c < columnsCount; c++)
|
|
{
|
|
var dc = table.Columns[c];
|
|
var column = Json.NewObject();
|
|
column.SetProperty("name", dc.ColumnName);
|
|
column.SetProperty("type", dc.DataType.FullName);
|
|
columns.AddItem(column);
|
|
}
|
|
|
|
var rowsCount = table.Rows.Count;
|
|
for (var r = 0; r < rowsCount; r++)
|
|
{
|
|
var row = Json.NewArray();
|
|
for (var c = 0; c < columnsCount; c++)
|
|
{
|
|
var v = Value(r, c);
|
|
if (v == null) row.AddItem();
|
|
else if (v.Equals(DBNull.Value)) row.AddItem();
|
|
else if (v is byte vByte) row.AddItem(vByte);
|
|
else if (v is short vInt16) row.AddItem(vInt16);
|
|
else if (v is int vInt32) row.AddItem(vInt32);
|
|
else if (v is long vInt64) row.AddItem(vInt64);
|
|
else if (v is float vSingle) row.AddItem(vSingle);
|
|
else if (v is double vDouble) row.AddItem(vDouble);
|
|
else if (v is decimal vDecimal) row.AddItem(vDecimal);
|
|
else if (v is bool vBoolean) row.AddItem(vBoolean);
|
|
else if (v is byte[] vBytes) row.AddItem(vBytes.Base64());
|
|
else if (v is DateTime vDateTime) row.AddItem(vDateTime.Lucid());
|
|
else row.AddItem(v.ToString());
|
|
}
|
|
rows.AddItem(row);
|
|
}
|
|
}
|
|
|
|
var jsonObject = Json.NewObject();
|
|
jsonObject.SetProperty("success", _success);
|
|
jsonObject.SetProperty("message", _message);
|
|
jsonObject.SetProperty("columns", columns);
|
|
jsonObject.SetProperty("rows", rows);
|
|
return jsonObject;
|
|
}
|
|
|
|
/// <summary>转换为模型数组。</summary>
|
|
public ObjectSet[] ToArray()
|
|
{
|
|
var oss = null as ObjectSet[];
|
|
var table = _table;
|
|
if (!_disposed && table != null)
|
|
{
|
|
var width = table.Columns.Count;
|
|
var names = new string[width];
|
|
for (var c = 0; c < width; c++)
|
|
{
|
|
var name = table.Columns[c].ColumnName;
|
|
if (name.IsEmpty()) continue;
|
|
if (names.Contains(name)) continue;
|
|
names[c] = name;
|
|
}
|
|
|
|
var unnamed = 1;
|
|
for (var c = 0; c < width; c++)
|
|
{
|
|
if (names[c] != null) continue;
|
|
while (true)
|
|
{
|
|
var name = "unnamed_" + unnamed.ToString();
|
|
unnamed++;
|
|
if (names.Contains(name)) continue;
|
|
names[c] = name;
|
|
break;
|
|
}
|
|
}
|
|
|
|
var height = table.Rows.Count;
|
|
oss = new ObjectSet[height];
|
|
for (var r = 0; r < height; r++)
|
|
{
|
|
var os = new ObjectSet();
|
|
var dict = os.Origin;
|
|
for (var c = 0; c < width; c++)
|
|
{
|
|
var v = Value(r, c);
|
|
dict.Add(names[c], v.IsNull() ? null : v);
|
|
}
|
|
oss[r] = os;
|
|
}
|
|
}
|
|
return oss;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Static
|
|
|
|
private static T ForceFormatter<T>(object input) => (T)input;
|
|
|
|
private static T TextFormatter<T>(object input) => (T)(Text(input) as object);
|
|
|
|
private static ObjectDisposedException DisposedException { get { return new ObjectDisposedException(typeof(Query).FullName); } }
|
|
|
|
#endregion
|
|
|
|
#region Extension
|
|
|
|
internal static string Text(object value)
|
|
{
|
|
if (value != null && !value.Equals(DBNull.Value))
|
|
{
|
|
if (value is string str) return str;
|
|
try { return value.ToString() ?? ""; } catch { }
|
|
}
|
|
return "";
|
|
}
|
|
|
|
internal static Class<DateTime> DateTime(object value)
|
|
{
|
|
if (value == null) return null;
|
|
if (value is DateTime) return null;
|
|
DateTime result;
|
|
var parsed = System.DateTime.TryParse(value.ToString(), out result);
|
|
return parsed ? new Class<DateTime>(result) : null;
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
}
|
|
|