using Apewer.Internals; using Apewer; using System; using System.Collections.Generic; using System.Data; using System.Reflection; using System.Text; namespace Apewer.Source { /// 表结构。 [Serializable] public sealed class TableStructure { #region Instance TableAttribute _attribute = null; bool _independent = false; string _name = null; string _description = null; bool _allprops = false; ColumnAttribute _key = null; ColumnAttribute _flag = null; ColumnAttribute[] _columns = null; Type _model = null; private TableStructure() { } /// 不依赖 Record 公共属性。 public bool Independent { get => _independent; } /// 表名称。 public string Name { get => _name; } /// 表的说明信息。 public string Description { get => _description; } /// 使用模型的所有属性,自动对属性添加缺少的 Column 特性。 public bool AllProperties { get => _allprops; } /// 此结构的特性。 public TableAttribute Attribute { get => _attribute; } /// 使用此结构的记录模型。 public Type Model { get => _model; } /// 主键。 public ColumnAttribute Key { get => _key; } /// 列信息。 public ColumnAttribute[] Columns { get => _columns; } #endregion #region TableStructure private static Dictionary _tsc = new Dictionary(); /// 解析表结构。 public static TableStructure Parse(bool useCache = true) where T : IRecord => Parse(typeof(T), useCache); /// 解析表结构。 public static TableStructure Parse(Type model, bool useCache = true) { var type = model; if (type == null || !type.IsClass || type.IsAbstract) return null; // 使用缓存。 var cacheKey = type.FullName; if (useCache) { lock (_tsc) { TableStructure cached; if (_tsc.TryGetValue(cacheKey, out cached)) return cached; } } // 获取 Table Attribute。 var ta = TableAttribute.Parse(type); // 遍历所有属性。 var properties = type.GetProperties(); var key = null as ColumnAttribute; var flag = null as ColumnAttribute; var columns = new ColumnAttribute[properties.Length]; var columnsCount = 0; if (properties.Length > 0) { var addedFields = new List(properties.Length); foreach (var property in properties) { // 解析 ColumnAttribute,抛弃无效。 var ca = ColumnAttribute.Parse(type, property, ta); if (ca == null) continue; // 检查 field 重复,只保留第一个。 var field = ca.Field; if (addedFields.Contains(field)) continue; addedFields.Add(field); if (property.Name == "Key") key = ca; if (property.Name == "Flag") flag = ca; columns[columnsCount] = ca; columnsCount += 1; } } if (columnsCount > 0 && columnsCount != columns.Length) columns = columns.Slice(0, columnsCount); // 排序,将 Key 和 Flag 排在最前。 columns = ColumnAttribute.Sort(columns); // 返回结果。 var ts = new TableStructure(); ts._attribute = ta; ts._key = key; ts._flag = flag; ts._name = ta.Name; ts._description = ta.Description; ts._allprops = ta.AllProperties; ts._independent = ta.Independent; ts._columns = columns; ts._model = model; // 加入缓存。 if (useCache) { lock (_tsc) { if (!_tsc.ContainsKey(cacheKey)) _tsc.Add(cacheKey, ts); } } return ts; } #endregion #region TableAttribute /// 限定表名称/列名称。 /// 名称。 /// 名称以下划线开始。 internal static string RestrictName(string name, bool startWithUnderline) { if (name == null || name == Constant.EmptyString) return Constant.EmptyString; var lower = name.ToLower(); var available = TextUtility.Merge("_", Constant.NumberCollection, Constant.LowerCollection); var sb = new StringBuilder(); foreach (var c in lower) { if (available.IndexOf(c) >= 0) sb.Append(c); } lower = sb.ToString(); if (startWithUnderline && !lower.StartsWith("_")) lower = TextUtility.Merge("_", lower); while (lower.Length > 2 && lower.StartsWith("__")) lower = lower.Substring(1); if (lower == "_" || lower == Constant.EmptyString) return Constant.EmptyString; if (lower.Length > 255) lower = lower.Substring(0, 255); return lower; } static IDataParameter CreateParameter(IRecord record, ColumnAttribute ca, Func callback) { var property = ca.Property; if (property == null) return null; var getter = property.GetGetMethod(); if (getter == null) return null; var value = getter.Invoke(record, null); if (ca.Type == ColumnType.Bytes || ca.Type == ColumnType.Integer || ca.Type == ColumnType.Float) { return callback(new Parameter(ca.Field, value, ca.Type, ca.Length)); } if (ca.Type == ColumnType.DateTime) { return callback(new Parameter(ca.Field, value, ca.Type, 0)); } if (property.PropertyType.Equals(typeof(String))) { var text = value as string; if (text == null) text = ""; if (ca.Length > 0) { switch (ca.Type) { case ColumnType.VarChar: case ColumnType.NVarChar: text = TextUtility.Left(text, ca.Length); break; case ColumnType.VarChar191: case ColumnType.NVarChar191: text = TextUtility.Left(text, 191); break; } } return callback(new Parameter(ca.Field, text, ca.Type, ca.Length)); } var defaultText = (value == null) ? TextUtility.Empty : value.ToString(); return callback(new Parameter(ca.Field, defaultText, ca.Type, ca.Length)); } /// 生成 IDataParameter 列表,用于 Insert 和 Update 方法。 public IDataParameter[] CreateParameters(IRecord record, Func callback, params string[] excludeds) { if (record == null || callback == null) return null; record.FixProperties(); var list = new List(_columns.Length); foreach (var ca in Columns) { if (ca == null) continue; var parameter = CreateParameter(record, ca, callback); if (parameter == null) continue; var add = true; if (excludeds != null) { var lower = parameter.ParameterName.ToLower(); foreach (var excluded in excludeds) { if (string.IsNullOrEmpty(excluded)) continue; if (lower == excluded.ToLower()) { add = false; break; } } } if (add) list.Add(parameter); } return list.ToArray(); } #endregion } }