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
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
|
|
|
|
}
|
|
|
|
}
|
|
|