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) => OrmHelper.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) => OrmHelper.Column(this, (r) => (formatter ?? GetValueFormatter<T>()).Invoke(Value(r, column))); /// <summary>获取指定列的所有值,无效值不加入结果。</summary> public string[] ReadColumn(int column = 0) => OrmHelper.Column(this, (r) => this.Text(r, column)); /// <summary>获取指定列的所有值,无效值不加入结果。</summary> /// <exception cref="ArgumentNullException"></exception> public string[] ReadColumn(string column) => OrmHelper.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 < _table.Rows.Count; 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; } #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); } } /// <summary>简单查询:取结果中第 0 列所有单元格的文本形式,可指定查询后关闭服务器连接,返回结果中不包含无效文本。</summary> public static string[] SimpleColumn(IDbClientAdo database, string statement, bool dispose = false) { if (database == null) return new string[0]; var ab = new ArrayBuilder<string>(); using (var query = database.Query(statement)) { var rows = query.Rows; if (rows > 0) { var added = 0; for (int i = 0; i < rows; i++) { var cell = Trim(query.Text(i)); if (string.IsNullOrEmpty(cell)) continue; ab.Add(cell); added++; } } } if (dispose) RuntimeUtility.Dispose(database); return ab.Export(); } /// <summary>简单查询:取结果中第 0 行、第 0 列单元格中的文本,可指定查询后关闭服务器连接。</summary> public static string SimpleCell(IDbClientAdo database, string statement, bool dispose = false) { if (database == null) return ""; var query = database.Query(statement); var cell = Trim(Query.Text(query.Value())); query.Dispose(); if (dispose) RuntimeUtility.Dispose(database); return cell; } #endregion #region Extension internal static string Text(object value) { var result = Constant.EmptyString; if (value != null) { if (!value.Equals(DBNull.Value)) { try { result = value.ToString(); } finally { } } } return result; } 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 } }