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 sealed 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]; } /// <summary>从 <see cref="Query"/> 到 <see cref="Boolean"/> 的隐式转换,判断 <see cref="Query"/> 执行成功且包含表。</summary> public static implicit operator bool(Query query) => query != null && query.Success && query.Table != null; /// <summary>从 <see cref="DataTable"/> 到 <see cref="Query"/> 的隐式转换。</summary> public static implicit operator Query(DataTable table) => new Query(table, table != null, null); /// <summary>从 <see cref="Query"/> 到 <see cref="DataTable"/> 的隐式转换。</summary> public static implicit operator DataTable(Query query) => query?.Table; #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>获取默认表中指定单元格的内容。</summary> /// <param name="rowIndex">行索引,从 0 开始。</param> /// <param name="columnIndex">列索引,从 0 开始。</param> public object Value(int rowIndex, int columnIndex) => Table.Value(rowIndex, columnIndex); /// <summary>获取默认表中指定单元的内容。</summary> /// <param name="rowIndex">行索引,从 0 开始。</param> /// <param name="columnName">列名称/字段名称,此名称不区分大小写。</param> public object Value(int rowIndex, string columnName) => Table.Value(rowIndex, columnName); #endregion #region Method /// <summary>释放系统资源。</summary> public 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); } #endregion #region 模型化、IToJson /// <summary>转换为 Json 对象。</summary> public Json ToJson() { var jsonObject = Json.NewObject(); jsonObject.SetProperty("success", _success); jsonObject.SetProperty("message", _message); if (Table != null) { var columns = SourceUtility.ToJson(Table.Columns); jsonObject.SetProperty("columns", columns); var rows = SourceUtility.ToJson(Table.Rows); 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 } }