using System; using System.Collections.Generic; using System.Text; using static Apewer.NumberUtility; namespace Apewer.Source { /// ORM 帮助程序。 public static class OrmHelper { #region As /// 转换模型类型。 public static TDst[] As(this TSrc[] input) where TDst : class { if (input == null) return null; var count = input.Length; var output = new TDst[count]; for (var i = 0; i < count; i++) { var item = input[i]; if (item == null) continue; output[i] = item as TDst; // 此处可能抛出异常。 } return output; } /// 转换模型类型。 public static Result As(this Result input) where TDst : class { if (input == null) return null; if (!input.HasValue) return new Result(input.Code, input.Message); var value = input.Value as TDst; if (value == null) { var src = input.Value.GetType().FullName; var dst = typeof(TDst).FullName; return new Result($"无法将记录从转换 {src} 到 {dst}。"); } return new Result(value); } /// 转换模型类型。 public static Result As(this Result input) where TDst : class { if (input == null) return null; if (!input.HasValue) return new Result(input.Code, input.Message); var count = input.Value.Length; var output = new TDst[count]; for (var i = 0; i < count; i++) output[i] = input.Value[i] as TDst; return new Result(output); } #endregion #region IQuery -> IRecord /// 读取所有行,生成列表。 public static T[] Fill(IQuery query) where T : class, new() => As(Fill(query, typeof(T))); /// 读取所有行填充到 T,组成 T[]。 public static object[] Fill(IQuery query, Type model) { if (query == null) return new object[0]; if (model == null) return new object[0]; var ts = TableStructure.Parse(model); if (ts == null) return new object[0]; var output = new object[query.Rows]; for (int r = 0; r < query.Rows; r++) output[r] = Row(query, r, model, ts); return output; } /// 获取指定列的所有值,无效值不加入结果。 public static T[] Column(IQuery query, Func filler) { if (query == null || filler == null) return new T[0]; var rows = query.Rows; var output = new T[rows]; var added = 0; for (int r = 0; r < rows; r++) { var value = filler(r); if (value == null) continue; if (value is string str) { if (str == "") continue; } output[added] = value; added++; } if (added < 1) return new T[0]; if (added == rows) return output; var output2 = new T[added]; Array.Copy(output, output2, added); return output2; } /// 将 Query 的行,填充到模型实体。 /// 填充失败时返回 NULL 值。 /// public static IRecord Row(IQuery query, int rowIndex, Type model, TableStructure structure) { // 检查参数。 if (query == null || model == null || structure == null) return null; if (rowIndex < 0 || rowIndex >= query.Rows) return null; if (!RuntimeUtility.CanNew(model)) return null; // 变量别名。 var ts = structure; var r = rowIndex; var columns = ts.Columns; // 检查模型的属性,按属性从表中取相应的列。 var record = Activator.CreateInstance(model); var properties = model.GetProperties(); foreach (var property in properties) { // 必须有 setter 访问器。 var setter = property.GetSetMethod(); if (setter == null) continue; // 在表结构中检查,是否包含此属性,并获取 ColumnAttribute。 var attribute = null as ColumnAttribute; for (var j = 0; j < columns.Length; j++) { if (columns[j].PropertyName == property.Name) { attribute = columns[j]; break; } } if (attribute == null) continue; // 根据属性类型设置值。 var pt = property.PropertyType; if (pt.Equals(typeof(object)) || pt.Equals(typeof(Nullable))) { 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 { } } } return record as IRecord; } #endregion #region IOrm /// 查询记录。 /// 数据库对象。 /// 记录模型。 /// SQL 语句。 public static Result Query(IDbClientAdo database, Type model, string sql) { if (database == null) return new Result("数据库无效。"); if (model == null) return new Result("模型类型无效。"); if (string.IsNullOrEmpty(sql)) return new Result("SQL 语句无效。"); using (var query = database.Query(sql) as Query) { if (query == null) return new Result("查询实例无效。"); if (query.Table == null) { if (!string.IsNullOrEmpty(query.Message)) return new Result(query.Message); return new Result("查询实例不包含数据表。"); } try { var array = Fill(query, model); return new Result(array); } catch (Exception ex) { return new Result(ex); } } } /// 查询记录。 /// 记录模型。 /// 数据库对象。 /// SQL 语句。 public static Result Query(IDbClientAdo database, string sql) where T : class, new() => As(Query(database, typeof(T), sql)); /// 查询记录。 /// 数据库对象。 /// 记录模型。 /// 生成 SQL 语句的函数,传入参数为表名。 public static Result Query(IDbClientAdo database, Type model, Func sqlGetter) { if (sqlGetter == null) return new Result("SQL 语句获取函数无效。"); try { var tableName = TableStructure.Parse(model).Name; if (string.IsNullOrEmpty(tableName)) return new Result("表名无效。"); return Query(database, model, sqlGetter(tableName)); } catch (Exception ex) { return new Result(ex); } } /// 查询记录。 /// 记录模型。 /// 数据库对象。 /// 生成 SQL 语句的函数,传入参数为表名。 public static Result Query(IDbClientAdo database, Func sqlGetter) where T : class, new() => As(Query(database, typeof(T), sqlGetter)); /// 获取具有指定主键的记录。 /// 数据库对象。 /// 记录模型。 /// 主键。 /// 生成 SQL 语句的函数,传入参数为表名和主键值。 public static Result Get(IDbClientAdo database, Type model, string key, Func sqlGetter) { if (sqlGetter == null) return new Result("SQL 语句获取函数无效。"); var safetyKey = TextUtility.SafeKey(key); if (string.IsNullOrEmpty(safetyKey)) return new Result("主键无效。"); var query = null as IQuery; var record = null as IRecord; try { var ts = TableStructure.Parse(model); var tableName = ts.Name; if (string.IsNullOrEmpty(tableName)) return new Result("表名无效。"); var sql = sqlGetter(tableName, safetyKey); query = database.Query(sql); if (query.Table == null) return new Result("没有获取到记录。"); record = Row(query, 0, model, ts); } catch (Exception ex) { RuntimeUtility.Dispose(query); return new Result(ex); } RuntimeUtility.Dispose(query); if (record == null) return new Result("没有获取到记录。"); return new Result(record); } /// 获取具有指定主键的记录。 /// 记录模型。 /// 数据库对象。 /// 主键。 /// 生成 SQL 语句的函数,传入参数为表名和主键值。 public static Result Get(IDbClientAdo database, string key, Func sqlGetter) where T : class, IRecord, new() => As(Get(database, typeof(T), key, sqlGetter)); /// 获取主键。 /// 数据库对象。 /// 记录模型。 /// 生成 SQL 语句的函数,传入参数为表名。 public static Result Keys(IDbClientAdo database, Type model, Func sqlGetter) { if (database == null) return new Result("数据库无效。"); if (model == null) return new Result("模型类型无效。"); if (sqlGetter == null) return new Result("SQL 语句获取函数无效。"); var tableStructure = null as TableStructure; try { tableStructure = TableStructure.Parse(model); } catch (Exception ex) { return new Result(ex); } var tableName = tableStructure.Name; if (string.IsNullOrEmpty(tableName)) return new Result("表名无效。"); // 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>.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("查询实例无效。"); var list = new List(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; var array = list.ToArray(); return new Result(array); } catch (Exception ex) { RuntimeUtility.Dispose(query); return new Result(ex); } } /// 获取主键。 /// 记录模型。 /// 数据库对象。 /// 生成 SQL 语句的函数,传入参数为表名。 public static Result Keys(IDbClientAdo database, Func sqlGetter) where T : IRecord { return Keys(database, typeof(T), sqlGetter); } #endregion #region Record /// 修复记录属性。 public static void FixProperties(object record) { if (record == null) return; if (record is IRecord key) key.ResetKey(); if (record is IRecordMoment moment) { var now = ClockUtility.LucidNow; if (string.IsNullOrEmpty(moment.Created)) moment.Created = now; if (string.IsNullOrEmpty(moment.Updated)) moment.Updated = now; } if (record is IRecordStamp stamp) { var utc = ClockUtility.UtcStamp; if (stamp.Created == 0L) stamp.Created = utc; if (stamp.Updated == 0L) stamp.Updated = utc; } } /// 设置 Updated 属性。 /// TRUE:设置成功;FALSE:设置失败。 public static bool SetUpdated(object record) { if (record == null) return false; if (record is IRecordMoment moment) { var now = ClockUtility.LucidNow; moment.Updated = now; return true; } if (record is IRecordStamp stamp) { var utc = ClockUtility.UtcStamp; stamp.Updated = utc; return true; } return false; } #endregion } }