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.
379 lines
16 KiB
379 lines
16 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
|
|
using static Apewer.NumberUtility;
|
|
|
|
namespace Apewer.Source
|
|
{
|
|
|
|
/// <summary>ORM 帮助程序。</summary>
|
|
public static class OrmHelper
|
|
{
|
|
|
|
#region As
|
|
|
|
private static List<T> As<T>(List<IRecord> input) where T : IRecord
|
|
{
|
|
if (input == null) return null;
|
|
var output = new List<T>(input.Count);
|
|
foreach (var record in input)
|
|
{
|
|
if (record == null) continue;
|
|
var t = (T)record;
|
|
output.Add(t);
|
|
}
|
|
return output;
|
|
}
|
|
|
|
private static Result<T> As<T>(Result<IRecord> input) where T : class, IRecord, new()
|
|
{
|
|
if (input == null) return null;
|
|
if (!input.HasValue) return new Result<T>(input.Code, input.Message);
|
|
var value = input.Value as T;
|
|
return new Result<T>(value);
|
|
}
|
|
|
|
private static Result<List<T>> As<T>(Result<List<IRecord>> input) where T : class, IRecord, new()
|
|
{
|
|
if (input == null) return null;
|
|
if (!input.HasValue) return new Result<List<T>>(input.Code, input.Message);
|
|
var list = new List<T>(input.Value.Count);
|
|
foreach (var inputItem in input.Value)
|
|
{
|
|
var value = inputItem as T;
|
|
list.Add(value);
|
|
}
|
|
return new Result<List<T>>(list);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IQuery -> IRecord
|
|
|
|
/// <summary>读取所有行,生成列表。</summary>
|
|
public static List<T> Fill<T>(IQuery query) where T : class, IRecord, new() => As<T>(Fill(query, typeof(T)));
|
|
|
|
/// <summary>读取所有行填充到 T,组成 List<T>。</summary>
|
|
/// <exception cref="Exception"></exception>
|
|
public static List<IRecord> Fill(IQuery query, Type model)
|
|
{
|
|
if (query == null) return new List<IRecord>();
|
|
if (model == null) return new List<IRecord>();
|
|
|
|
var list = new List<IRecord>(query.Rows);
|
|
var ts = TableStructure.ParseModel(model);
|
|
for (int r = 0; r < query.Rows; r++)
|
|
{
|
|
var record = Row(query, r, model, ts);
|
|
if (record != null) list.Add(record);
|
|
}
|
|
list.Capacity = list.Count;
|
|
return list;
|
|
}
|
|
|
|
/// <summary>获取指定列的所有值,无效值不加入结果。</summary>
|
|
/// <exception cref="ArgumentNullException"></exception>
|
|
public static List<T> Column<T>(IQuery query, Func<int, T> filler)
|
|
{
|
|
if (query == null) throw new ArgumentNullException(nameof(query));
|
|
if (filler == null) throw new ArgumentNullException(nameof(filler));
|
|
|
|
var rows = query.Rows;
|
|
var list = new List<T>(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>
|
|
/// <remarks>填充失败时返回 NULL 值。</remarks>
|
|
/// <exception cref="Exception"></exception>
|
|
/// <exception cref="ArgumentNullException"></exception>
|
|
/// <exception cref="ArgumentOutOfRangeException"></exception>
|
|
public static IRecord Row(IQuery query, int rowIndex, Type model, TableStructure structure)
|
|
{
|
|
if (query == null) throw new ArgumentNullException(nameof(query));
|
|
if (model == null) throw new ArgumentNullException(nameof(model));
|
|
if (structure == null) throw new ArgumentNullException(nameof(structure));
|
|
if (rowIndex < 0 || rowIndex >= query.Rows) throw new ArgumentOutOfRangeException(nameof(rowIndex));
|
|
var record = Activator.CreateInstance(model);
|
|
var properties = model.GetProperties();
|
|
var ts = structure;
|
|
var r = rowIndex;
|
|
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(record, new object[] { query.Value(r, attribute.Field) });
|
|
}
|
|
else if (pt.Equals(typeof(DateTime)))
|
|
{
|
|
var value = query.Value(r, attribute.Field);
|
|
if (value != null) setter.Invoke(record, new object[] { query.Value(r, attribute.Field) });
|
|
}
|
|
else if (pt.Equals(typeof(byte[])))
|
|
{
|
|
setter.Invoke(record, new object[] { (byte[])query.Value(r, attribute.Field) });
|
|
}
|
|
else if (pt.Equals(typeof(byte)))
|
|
{
|
|
setter.Invoke(record, new object[] { Byte(query.Text(r, attribute.Field)) });
|
|
}
|
|
else if (pt.Equals(typeof(sbyte)))
|
|
{
|
|
setter.Invoke(record, new object[] { SByte(query.Text(r, attribute.Field)) });
|
|
}
|
|
else if (pt.Equals(typeof(short)))
|
|
{
|
|
setter.Invoke(record, new object[] { Int16(query.Text(r, attribute.Field)) });
|
|
}
|
|
else if (pt.Equals(typeof(ushort)))
|
|
{
|
|
setter.Invoke(record, new object[] { UInt16(query.Text(r, attribute.Field)) });
|
|
}
|
|
else if (pt.Equals(typeof(int)))
|
|
{
|
|
setter.Invoke(record, new object[] { Int32(query.Text(r, attribute.Field)) });
|
|
}
|
|
else if (pt.Equals(typeof(uint)))
|
|
{
|
|
setter.Invoke(record, new object[] { UInt32(query.Text(r, attribute.Field)) });
|
|
}
|
|
else if (pt.Equals(typeof(long)))
|
|
{
|
|
setter.Invoke(record, new object[] { Int64(query.Text(r, attribute.Field)) });
|
|
}
|
|
else if (pt.Equals(typeof(ulong)))
|
|
{
|
|
setter.Invoke(record, new object[] { UInt64(query.Text(r, attribute.Field)) });
|
|
}
|
|
else if (pt.Equals(typeof(float)))
|
|
{
|
|
setter.Invoke(record, new object[] { Single(query.Text(r, attribute.Field)) });
|
|
}
|
|
else if (pt.Equals(typeof(double)))
|
|
{
|
|
setter.Invoke(record, new object[] { Double(query.Text(r, attribute.Field)) });
|
|
}
|
|
else if (pt.Equals(typeof(decimal)))
|
|
{
|
|
setter.Invoke(record, new object[] { Decimal(query.Text(r, attribute.Field)) });
|
|
}
|
|
else if (pt.Equals(typeof(string)))
|
|
{
|
|
setter.Invoke(record, new object[] { query.Text(r, attribute.Field) });
|
|
}
|
|
else
|
|
{
|
|
try
|
|
{
|
|
setter.Invoke(record, new object[] { query.Value(r, attribute.Field) });
|
|
}
|
|
catch { }
|
|
}
|
|
}
|
|
var iRecord = record as IRecord;
|
|
return iRecord;
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region IOrm
|
|
|
|
/// <summary>查询记录。</summary>
|
|
/// <param name="database">数据库对象。</param>
|
|
/// <param name="model">记录模型。</param>
|
|
/// <param name="sql">SQL 语句。</param>
|
|
public static Result<List<IRecord>> Query(IDatabaseQuery database, Type model, string sql)
|
|
{
|
|
if (database == null) return new Result<List<IRecord>>("数据库无效。");
|
|
if (model == null) return new Result<List<IRecord>>("模型类型无效。");
|
|
if (string.IsNullOrEmpty(sql)) return new Result<List<IRecord>>("SQL 语句无效。");
|
|
using (var query = database.Query(sql) as Query)
|
|
{
|
|
if (query == null) return new Result<List<IRecord>>("查询实例无效。");
|
|
if (query.Exception != null) return new Result<List<IRecord>>(query.Exception);
|
|
try
|
|
{
|
|
var list = Fill(query, model);
|
|
return new Result<List<IRecord>>(list);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return new Result<List<IRecord>>(ex);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>查询记录。</summary>
|
|
/// <typeparam name="T">记录模型。</typeparam>
|
|
/// <param name="database">数据库对象。</param>
|
|
/// <param name="sql">SQL 语句。</param>
|
|
public static Result<List<T>> Query<T>(IDatabaseQuery database, string sql) where T : class, IRecord, new() => As<T>(Query(database, typeof(T), sql));
|
|
|
|
/// <summary>查询记录。</summary>
|
|
/// <param name="database">数据库对象。</param>
|
|
/// <param name="model">记录模型。</param>
|
|
/// <param name="sqlGetter">生成 SQL 语句的函数,传入参数为表名。</param>
|
|
public static Result<List<IRecord>> Query(IDatabaseQuery database, Type model, Func<string, string> sqlGetter)
|
|
{
|
|
if (sqlGetter == null) return new Result<List<IRecord>>("SQL 语句获取函数无效。");
|
|
try
|
|
{
|
|
var tableName = TableStructure.ParseModel(model).Table;
|
|
if (string.IsNullOrEmpty(tableName)) return new Result<List<IRecord>>("表名无效。");
|
|
return Query(database, model, sqlGetter(tableName));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return new Result<List<IRecord>>(ex);
|
|
}
|
|
}
|
|
|
|
/// <summary>查询记录。</summary>
|
|
/// <typeparam name="T">记录模型。</typeparam>
|
|
/// <param name="database">数据库对象。</param>
|
|
/// <param name="sqlGetter">生成 SQL 语句的函数,传入参数为表名。</param>
|
|
public static Result<List<T>> Query<T>(IDatabaseQuery database, Func<string, string> sqlGetter) where T : class, IRecord, new() => As<T>(Query(database, typeof(T), sqlGetter));
|
|
|
|
/// <summary>获取具有指定主键的记录。</summary>
|
|
/// <param name="database">数据库对象。</param>
|
|
/// <param name="model">记录模型。</param>
|
|
/// <param name="key">主键。</param>
|
|
/// <param name="sqlGetter">生成 SQL 语句的函数,传入参数为表名和主键值。</param>
|
|
public static Result<IRecord> Get(IDatabaseQuery database, Type model, string key, Func<string, string, string> sqlGetter)
|
|
{
|
|
if (sqlGetter == null) return new Result<IRecord>("SQL 语句获取函数无效。");
|
|
|
|
var safetyKey = TextUtility.SafeKey(key);
|
|
if (string.IsNullOrEmpty(safetyKey)) return new Result<IRecord>("主键无效。");
|
|
|
|
var query = null as IQuery;
|
|
var record = null as IRecord;
|
|
try
|
|
{
|
|
var ts = TableStructure.ParseModel(model);
|
|
var tableName = ts.Table;
|
|
if (string.IsNullOrEmpty(tableName)) return new Result<IRecord>("表名无效。");
|
|
var sql = sqlGetter(tableName, safetyKey);
|
|
|
|
query = database.Query(sql);
|
|
if (query.Table == null) return new Result<IRecord>("没有获取到记录。");
|
|
record = Row(query, 0, model, ts);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
RuntimeUtility.Dispose(query);
|
|
return new Result<IRecord>(ex);
|
|
}
|
|
RuntimeUtility.Dispose(query);
|
|
if (record == null) return new Result<IRecord>("没有获取到记录。");
|
|
return new Result<IRecord>(record);
|
|
}
|
|
|
|
/// <summary>获取具有指定主键的记录。</summary>
|
|
/// <typeparam name="T">记录模型。</typeparam>
|
|
/// <param name="database">数据库对象。</param>
|
|
/// <param name="key">主键。</param>
|
|
/// <param name="sqlGetter">生成 SQL 语句的函数,传入参数为表名和主键值。</param>
|
|
public static Result<T> Get<T>(IDatabaseQuery database, string key, Func<string, string, string> sqlGetter) where T : class, IRecord, new() => As<T>(Get(database, typeof(T), key, sqlGetter));
|
|
|
|
/// <summary>获取主键。</summary>
|
|
/// <param name="database">数据库对象。</param>
|
|
/// <param name="model">记录模型。</param>
|
|
/// <param name="sqlGetter">生成 SQL 语句的函数,传入参数为表名。</param>
|
|
public static Result<List<string>> Keys(IDatabaseQuery database, Type model, Func<string, string> sqlGetter)
|
|
{
|
|
if (database == null) return new Result<List<string>>("数据库无效。");
|
|
if (model == null) return new Result<List<string>>("模型类型无效。");
|
|
if (sqlGetter == null) return new Result<List<string>>("SQL 语句获取函数无效。");
|
|
|
|
var tableStructure = null as TableStructure;
|
|
try
|
|
{
|
|
tableStructure = TableStructure.ParseModel(model);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return new Result<List<string>>(ex);
|
|
}
|
|
|
|
var tableName = tableStructure.Table;
|
|
if (string.IsNullOrEmpty(tableName)) return new Result<List<string>>("表名无效。");
|
|
|
|
// var keyName = null as string;
|
|
// foreach (var column in tableStructure.Columns)
|
|
// {
|
|
// if (column.Key == "Key")
|
|
// {
|
|
// keyName = column.Value.Field;
|
|
// break;
|
|
// }
|
|
// }
|
|
// if (string.IsNullOrEmpty(keyName)) return Result<List<string>>.Error("主键字段无效。");
|
|
|
|
// var sql = sqlGetter(tableName, keyName);
|
|
var sql = sqlGetter(tableName);
|
|
var query = null as IQuery;
|
|
try
|
|
{
|
|
query = database.Query(sql);
|
|
if (query == null) return new Result<List<string>>("查询实例无效。");
|
|
|
|
var list = new List<string>(query.Rows);
|
|
for (var r = 0; r < query.Rows; r++)
|
|
{
|
|
var key = TextUtility.SafeKey(query.Text(r));
|
|
if (string.IsNullOrEmpty(key)) continue;
|
|
list.Add(key);
|
|
}
|
|
query.Dispose();
|
|
list.Capacity = list.Count;
|
|
return new Result<List<string>>(list);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
RuntimeUtility.Dispose(query);
|
|
return new Result<List<string>>(ex);
|
|
}
|
|
}
|
|
|
|
/// <summary>获取主键。</summary>
|
|
/// <typeparam name="T">记录模型。</typeparam>
|
|
/// <param name="database">数据库对象。</param>
|
|
/// <param name="sqlGetter">生成 SQL 语句的函数,传入参数为表名。</param>
|
|
public static Result<List<string>> Keys<T>(IDatabaseQuery database, Func<string, string> sqlGetter) where T : IRecord
|
|
{
|
|
return Keys(database, typeof(T), sqlGetter);
|
|
}
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
}
|
|
|