|
|
using Apewer.Internals; using Apewer; using System; using System.Collections.Generic; using System.Data; using System.Reflection; using System.Text;
namespace Apewer.Source {
/// <summary>表结构。</summary>
[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() { }
/// <summary>不依赖 Record 公共属性。</summary>
public bool Independent { get => _independent; }
/// <summary>表名称。</summary>
public string Name { get => _name; }
/// <summary>表的说明信息。</summary>
public string Description { get => _description; }
/// <summary>使用模型的所有属性,自动对属性添加缺少的 Column 特性。</summary>
public bool AllProperties { get => _allprops; }
/// <summary>此结构的特性。</summary>
public TableAttribute Attribute { get => _attribute; }
/// <summary>使用此结构的记录模型。</summary>
public Type Model { get => _model; }
/// <summary>主键。</summary>
public ColumnAttribute Key { get => _key; }
/// <summary>记录标记。</summary>
public ColumnAttribute Flag { get => _flag; }
/// <summary>列信息。</summary>
public ColumnAttribute[] Columns { get => _columns; }
#endregion
#region TableStructure
private static Dictionary<string, TableStructure> _tsc = new Dictionary<string, TableStructure>();
/// <summary>解析表结构。</summary>
public static TableStructure Parse<T>(bool useCache = true) where T : IRecord => Parse(typeof(T), useCache);
/// <summary>解析表结构。</summary>
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<string>(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
// 限定表名称/列名称。
static string RestrictName(string name, bool underline = false, bool english = false) { if (string.IsNullOrEmpty(name)) return null; var str = name;
// 限定名称仅使用英文和数字。
if (english) { const string available = "_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; var chars = new ArrayBuilder<char>(); var strChars = str.ToCharArray(); var strLength = strChars.Length > 255 ? 255 : strChars.Length; for (var i = 0; i < strLength; i++) { if (available.IndexOf(strChars[i]) > -1) chars.Add(strChars[i]); } str = new string(chars.Export()); }
// 以下划线开始。
if (underline) { if (!str.StartsWith("_")) str = TextUtility.Merge("_", str); } return str; }
static IDataParameter CreateParameter(object record, ColumnAttribute ca, Func<Parameter, IDataParameter> 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)); }
/// <summary>生成 IDataParameter 列表,用于 Insert 和 Update 方法。</summary>
public IDataParameter[] CreateParameters(object record, Func<Parameter, IDataParameter> callback, params string[] excludeds) { if (record == null || callback == null) return null;
var list = new List<IDataParameter>(_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
}
}
|