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.

637 lines
23 KiB

using Apewer;
using Apewer.Internals;
using System;
using System.Collections.Generic;
using System.Data;
using System.Runtime.CompilerServices;
namespace Apewer.Source
{
/// <summary>查询数据表。</summary>
public class Query : IQuery, IDisposable
{
private bool _disposed = false;
private bool _success = false;
private string _error = "";
private string _message = "";
private Exception _exception = null;
private List<DataTable> _tables = new List<DataTable>();
#region Property
/// <summary>语句执行成功。</summary>
public bool Success
{
get
{
if (_disposed) return false;
return _success;
}
set
{
if (_disposed) return;
_success = value;
}
}
/// <summary>错误信息。</summary>
public string Error
{
get
{
if (_disposed) return "";
if (!string.IsNullOrEmpty(_error)) return _error;
if (_exception == null) return "";
var error = "";
try { error = _exception.Message; } finally { }
return error;
}
set
{
if (_disposed) return;
_error = value ?? "";
}
}
/// <summary>消息。</summary>
public string Message
{
get
{
if (_disposed) return "";
return _message ?? "";
}
set
{
if (_disposed) return;
_message = value ?? "";
}
}
/// <summary>语句执行失败时的 Exception 对象。</summary>
public Exception Exception
{
get { if (_disposed) return null; return _exception; }
set { if (_disposed) return; _exception = value; }
}
/// <summary>所有结果表。</summary>
public List<DataTable> Tables
{
get { if (_disposed) return new List<DataTable>(); return _tables; }
}
/// <summary>获取默认结果表。如果设置默认结果表,会丢失设置前的所有结果表。</summary>
public DataTable Table
{
get
{
if (_disposed) return null;
if (_tables.Count < 1) return null;
return _tables[0];
}
set
{
if (_disposed) return;
Clear();
if (_disposed) return;
_tables.Add(value);
}
}
/// <summary>所有表中不含内容行。</summary>
public bool Empty
{
get
{
if (_disposed) return true;
if (_tables.Count < 1) return true;
foreach (var table in _tables)
{
if (table == null) continue;
try
{
if (table.Rows.Count > 0) return false;
}
finally { }
}
return true;
}
}
/// <summary>默认表中的数据总行数。</summary>
public int Rows
{
get
{
if (_disposed) return 0;
if (Table != null) return Table.Rows.Count;
else return 0;
}
}
/// <summary>默认表中的数据总列数。</summary>
public int Columns
{
get
{
if (_disposed) return 0;
if (Table != null) return Table.Columns.Count;
else return 0;
}
}
#endregion
#region Text
/// <summary>获取默认表中第 0 行、第 0 列的单元格内容。</summary>
public string Text()
{
if (_disposed) return Constant.EmptyString;
var value = Value();
return Text(value);
}
/// <summary>获取默认表中指定行中第 0 列的内容。</summary>
/// <param name="rowIndex">行索引,从 0 开始。</param>
public string Text(int rowIndex)
{
if (_disposed) return Constant.EmptyString;
var value = Value(rowIndex);
return Text(value);
}
/// <summary>获取默认表中第 0 行指定列的内容。</summary>
/// <param name="columnName">列名称。</param>
public string Text(string columnName)
{
if (_disposed) return Constant.EmptyString;
var value = Value(columnName);
return Text(value);
}
/// <summary>获取默认表中指定单元格的内容。</summary>
/// <param name="rowIndex">行索引,从 0 开始。</param>
/// <param name="columnIndex">列索引,从 0 开始。</param>
public string Text(int rowIndex, int columnIndex)
{
if (_disposed) return Constant.EmptyString;
var value = Value(rowIndex, columnIndex);
return Text(value);
}
/// <summary>获取默认表中指定单元的内容。</summary>
/// <param name="rowIndex">行索引,从 0 开始。</param>
/// <param name="columnName">列名称。</param>
public string Text(int rowIndex, string columnName)
{
if (_disposed) return Constant.EmptyString;
var value = Value(rowIndex, columnName);
return Text(value);
}
/// <summary>搜索默认表。</summary>
/// <param name="conditionColumn">搜索条件:列名。</param>
/// <param name="conditionValue">搜索条件:列值。</param>
/// <param name="resultColumn">搜索结果。</param>
public string Text(string conditionColumn, string conditionValue, string resultColumn)
{
if (_disposed) return Constant.EmptyString;
var value = Value(conditionColumn, conditionValue, resultColumn);
return Text(value);
}
/// <summary>搜索默认表。</summary>
/// <param name="conditionColumn">搜索条件:列名。</param>
/// <param name="conditionValue">搜索条件:列值。</param>
/// <param name="resultColumn">搜索结果。</param>
public string Text(int conditionColumn, string conditionValue, int resultColumn)
{
if (_disposed) return Constant.EmptyString;
var value = Value(conditionColumn, conditionValue, resultColumn);
return Text(value);
}
#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>
public List<Query> Split()
{
var list = new List<Query>();
if (_disposed) return list;
foreach (var table in _tables)
{
if (table == null) continue;
var query = new Query();
query._success = true;
query._tables.Add(table);
list.Add(query);
}
return list;
}
/// <summary>添加数据表。</summary>
public bool Add(DataTable tables)
{
if (_disposed) return false;
if (tables == null) return false;
_tables.Add(tables);
return true;
}
/// <summary>添加数据表。</summary>
public int Add(IEnumerable<DataTable> tables)
{
var count = 0;
if (_disposed) return count;
if (tables == null) return count;
foreach (var table in tables)
{
if (table == null) continue;
_tables.Add(table);
count = count + 1;
}
return count;
}
/// <summary>清除所有表,并释放系统资源。</summary>
public virtual void Clear()
{
if (_tables != null)
{
foreach (var table in _tables)
{
if (table != null)
{
try { table.Dispose(); } catch { }
}
}
_tables.Clear();
}
if (_exception != null) _exception = null;
_success = false;
}
/// <summary>释放系统资源。</summary>
public virtual void Dispose()
{
Clear();
_disposed = true;
// GC.SuppressFinalize(this);
}
/// <summary></summary>
/// <exception cref="Exception"></exception>
public List<T> Fill<T>() where T : IRecord => Fill(typeof(T)) as List<T>;
/// <summary></summary>
/// <exception cref="Exception"></exception>
public List<IRecord> Fill(Type model)
{
var type = model;
var list = new List<IRecord>();
for (int r = 0; r < Rows; r++)
{
list.Capacity = Rows;
var entity = type.Assembly.CreateInstance(type.FullName);
var ts = TableStructure.ParseModel(type);
var properties = type.GetProperties();
foreach (var property in properties)
{
if (ts.Columns.ContainsKey(property.Name) == false) continue;
var setter = property.GetSetMethod();
if (setter == null) continue;
var attribute = ts.Columns[property.Name];
var pt = property.PropertyType;
if (pt.Equals(typeof(object)) || pt.Equals(typeof(Nullable<DateTime>)))
{
setter.Invoke(entity, new object[] { Value(r, attribute.Field) });
}
else if (pt.Equals(typeof(DateTime)))
{
var value = Value(r, attribute.Field);
if (value != null) setter.Invoke(entity, new object[] { Value(r, attribute.Field) });
}
else if (pt.Equals(typeof(byte[])))
{
setter.Invoke(entity, new object[] { (byte[])Value(r, attribute.Field) });
}
else if (pt.Equals(typeof(byte)))
{
setter.Invoke(entity, new object[] { TextConverter.GetByte(Text(r, attribute.Field)) });
}
else if (pt.Equals(typeof(sbyte)))
{
setter.Invoke(entity, new object[] { TextConverter.GetSByte(Text(r, attribute.Field)) });
}
else if (pt.Equals(typeof(short)))
{
setter.Invoke(entity, new object[] { TextConverter.GetInt16(Text(r, attribute.Field)) });
}
else if (pt.Equals(typeof(ushort)))
{
setter.Invoke(entity, new object[] { TextConverter.GetUInt16(Text(r, attribute.Field)) });
}
else if (pt.Equals(typeof(int)))
{
setter.Invoke(entity, new object[] { TextConverter.GetInt32(Text(r, attribute.Field)) });
}
else if (pt.Equals(typeof(uint)))
{
setter.Invoke(entity, new object[] { TextConverter.GetUInt32(Text(r, attribute.Field)) });
}
else if (pt.Equals(typeof(long)))
{
setter.Invoke(entity, new object[] { TextConverter.GetInt64(Text(r, attribute.Field)) });
}
else if (pt.Equals(typeof(ulong)))
{
setter.Invoke(entity, new object[] { TextConverter.GetUInt64(Text(r, attribute.Field)) });
}
else if (pt.Equals(typeof(float)))
{
setter.Invoke(entity, new object[] { TextConverter.GetSingle(Text(r, attribute.Field)) });
}
else if (pt.Equals(typeof(double)))
{
setter.Invoke(entity, new object[] { TextConverter.GetDouble(Text(r, attribute.Field)) });
}
else if (pt.Equals(typeof(decimal)))
{
setter.Invoke(entity, new object[] { TextConverter.GetDecimal(Text(r, attribute.Field)) });
}
else if (pt.Equals(typeof(string)))
{
setter.Invoke(entity, new object[] { Text(r, attribute.Field) });
}
else
{
try
{
setter.Invoke(entity, new object[] { Value(r, attribute.Field) });
}
catch { }
}
}
var iRecord = entity as IRecord;
if (iRecord != null) list.Add(iRecord);
}
return list;
}
/// <summary>获取指定列的所有值,无效值不加入结果。</summary>
/// <exception cref="ArgumentNullException"></exception>
public List<T> ReadColumn<T>(Func<int, T> filler)
{
var list = new List<T>();
if (filler == null) throw new ArgumentNullException(nameof(filler));
var rows = Rows;
if (rows > 0)
{
list.Capacity = rows;
var added = 0;
for (int r = 0; r < rows; r++)
{
var value = filler(r);
if (value == null) continue;
if (value is string)
{
var valueString = value as string;
if (string.IsNullOrEmpty(valueString)) continue;
}
list.Add(value);
added++;
}
list.Capacity = added;
}
return list;
}
/// <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 List<T> ReadColumn<T>(int column = 0, Func<object, T> formatter = null) => ReadColumn((r) => (formatter ?? GetValueFormatter<T>()).Invoke(Value(r, column)));
/// <summary>获取指定列的所有值,无效值不加入结果。</summary>
/// <exception cref="ArgumentNullException"></exception>
public List<T> ReadColumn<T>(string column, Func<object, T> formatter = null) => ReadColumn((r) => (formatter ?? GetValueFormatter<T>()).Invoke(Value(r, column)));
/// <summary>获取指定列的所有值,无效值不加入结果。</summary>
public List<string> ReadColumn(int column = 0) => ReadColumn((r) => Text(r, column));
/// <summary>获取指定列的所有值,无效值不加入结果。</summary>
/// <exception cref="ArgumentNullException"></exception>
public List<string> ReadColumn(string column) => ReadColumn((r) => Text(r, column));
#endregion
#region Static
private static string Text(object value)
{
var result = Constant.EmptyString;
if (value != null)
{
if (!value.Equals(DBNull.Value))
{
try
{
result = value.ToString();
}
finally { }
}
}
return result;
}
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 List<string> SimpleColumn(IDatabase database, string statement, bool close = false)
{
var list = new List<string>();
if (database == null) return list;
if (!database.Connect()) return list;
using (var query = database.Query(statement))
{
var rows = query.Rows;
if (rows > 0)
{
list.Capacity = query.Rows;
var added = 0;
for (int i = 0; i < rows; i++)
{
var cell = TextModifier.Trim(query.Text(i));
if (string.IsNullOrEmpty(cell)) continue;
list.Add(cell);
added++;
}
list.Capacity = added;
}
}
if (close) database.Close();
return list;
}
/// <summary>简单查询:取结果中第 0 行、第 0 列单元格中的文本,可指定查询后关闭服务器连接。</summary>
public static string SimpleCell(IDatabase database, string statement, bool close = false)
{
if (database == null) return "";
if (!database.Connect()) return "";
var vquery = database.Query(statement);
var vcell = TextModifier.Trim(vquery.Text());
vquery.Dispose();
if (close) database.Close();
return vcell;
}
#endregion
#region Extension
/// <summary></summary>
internal static DateTime DateTime(IQuery query, int row, string column)
{
if (query == null) return ClockUtility.Origin;
var value = query.Value(row, column);
if (value == null) return ClockUtility.Origin;
if (value is DateTime) return (DateTime)value;
DateTime result;
var parsed = System.DateTime.TryParse(value.ToString(), out result);
return parsed ? result : ClockUtility.Origin;
}
#endregion
}
}