|
|
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 {
private bool _locked = false;
private string _tablename = Constant.EmptyString; private bool _independent = false;
private Dictionary<string, ColumnAttribute> _columns = new Dictionary<string, ColumnAttribute>();
internal TableStructure() { }
/// <summary>不依赖 Record 公共属性。</summary>
public bool Independent { get { return _independent; } private set { _independent = value; } }
/// <summary>表名称。</summary>
public string Table { get { return _tablename; } private set { _tablename = value ?? ""; } }
/// <summary>列信息。</summary>
public Dictionary<string, ColumnAttribute> Columns { get { if (_locked) { var copy = new Dictionary<string, ColumnAttribute>(_columns.Count); foreach (var c in _columns) copy.Add(c.Key, c.Value); return copy; } return _columns; } private set { _columns = value; } }
/// <summary>锁定属性,阻止修改。</summary>
public void Lock() { _locked = true; foreach (var c in _columns) c.Value.Lock(); }
#region cache
private static Dictionary<string, TableStructure> _tsc = new Dictionary<string, TableStructure>();
private static Dictionary<string, TableAttribute> _tac = new Dictionary<string, TableAttribute>();
#endregion
#region static
/// <summary></summary>
/// <exception cref="System.Exception"></exception>
/// <exception cref="System.ArgumentNullException"></exception>
public static TableStructure ParseModel(object entity, bool useCache = true) { if (entity == null) throw new ArgumentNullException("参数无效"); var type = entity.GetType(); var result = ParseModel(type, useCache); return result; }
/// <summary></summary>
/// <exception cref="System.Exception"></exception>
/// <exception cref="System.ArgumentNullException"></exception>
public static TableStructure ParseModel<T>(bool useCache = true) where T : IRecord { return ParseModel(typeof(T), useCache); }
/// <summary></summary>
/// <exception cref="System.Exception"></exception>
/// <exception cref="System.ArgumentNullException"></exception>
public static TableStructure ParseModel(Type model, bool useCache = true) { var type = model; if (type == null) throw new ArgumentNullException("参数无效");
// 使用缓存。
var cacheKey = type.FullName; if (useCache) { var hint = null as TableStructure; lock (_tsc) { if (_tsc.ContainsKey(cacheKey)) { hint = _tsc[cacheKey]; } } if (hint != null) return hint; }
// 检查基类。
// if (type.BaseType.FullName.Equals(typeof(DatabaseRecord).FullName) == false) return "基类不受支持。";
// 检查 Attribute。
var ta = ParseTable(type);
// 获取所有属性。
var properties = type.GetProperties(); if (properties.LongLength < 1L) throw new Exception(TextGenerator.Merge("类 ", type.FullName, " 不包含属性。"));
// Record 根类属性名。
var roots = GetRootProperties();
// 检查字段定义。键:属性名称。
var columns = new Dictionary<string, ColumnAttribute>(); foreach (var property in properties) { var ca = ParseColumn(type, property); if (ca == null) continue;
// 检查冗余。
foreach (var column in columns) { if (column.Value.Field == ca.Field) { throw new Exception(TextGenerator.Merge("类 ", type.FullName, " 中,属性 ", property.Name, " 的列名称存在冗余。")); } }
// 检查基类。
if (roots.Contains(ca.Property.Name)) ca.Independent = true;
columns.Add(property.Name, ca); } // if (columns.Count < 1) throw new Exception(TextGenerator.Merge("类 ", type.FullName, " 不包含可用的列。"));
// 排序。
columns = SortColumns(columns);
// 返回结果。
var ts = new TableStructure(); ts.Table = ta.Name; ts.Independent = ta.Independent; ts.Columns = columns;
// 锁定属性。
ts.Lock();
// 加入缓存。
if (useCache) { lock (_tsc) { if (!_tsc.ContainsKey(cacheKey)) { _tsc.Add(cacheKey, ts); } } }
return ts; }
/// <summary></summary>
/// <param name="type"></param>
/// <exception cref="Exception"></exception>"
public static TableAttribute ParseTable<T>(bool useCache = true) where T : IRecord { return ParseTable(typeof(T), useCache); }
/// <summary></summary>
/// <param name="type"></param>
/// <exception cref="Exception"></exception>"
public static TableAttribute ParseTable(Type type, bool useCache = true) { // 使用缓存。
var cacheKey = type.FullName; if (useCache) { var hint = null as TableAttribute; lock (_tac) { if (_tac.ContainsKey(cacheKey)) { hint = _tac[cacheKey]; } } if (hint != null) return hint; }
var tas = type.GetCustomAttributes(typeof(TableAttribute), false); if (tas.LongLength < 1L) throw new Exception(TextGenerator.Merge("类 ", type.FullName, " 不包含 ", typeof(TableAttribute).FullName, "。")); if (tas.LongLength > 1L) throw new Exception(TextGenerator.Merge("类 ", type.FullName, " 包含多个 ", typeof(TableAttribute).FullName, "。"));
var ta = (TableAttribute)tas[0]; if (TextVerifier.IsBlank(ta.Name)) { ta = new TableAttribute("_" + type.Name); if (TextVerifier.IsBlank(ta.Name)) throw new Exception(TextGenerator.Merge("类 ", type.FullName, " 的表名称无效。")); }
ta.Independent = RuntimeUtility.ContainsAttribute<IndependentAttribute>(type, true);
// 锁定属性。
ta.Lock();
// 加入缓存。
if (useCache) { lock (_tac) { if (!_tac.ContainsKey(cacheKey)) { _tac.Add(cacheKey, ta); } } }
return ta; }
/// <summary></summary>
/// <exception cref="Exception">Exception</exception>"
public static ColumnAttribute ParseColumn(Type type, PropertyInfo property) { // 检查 Attributes。
var cas = property.GetCustomAttributes(typeof(ColumnAttribute), false); if (cas.LongLength < 1L) return null; if (cas.LongLength > 1L) throw new Exception(TextGenerator.Merge("类 ", type.FullName, " 中,属性 ", property.Name, " 包含多个 ", typeof(ColumnAttribute).FullName, "。")); var ca = (ColumnAttribute)cas[0];
// 检查列名称。
if (TextVerifier.IsBlank(ca.Field)) { ca = new ColumnAttribute("_" + property.Name, ca.Type, ca.Length, true); if (TextVerifier.IsBlank(ca.Field)) throw new Exception(TextGenerator.Merge("类 ", type.FullName, "中,属性 ", property.Name, " 的列名称无效。")); }
// 检查属性方法。
var getter = property.GetGetMethod(false); var setter = property.GetSetMethod(false); if (getter == null) throw new Exception(TextGenerator.Merge("类 ", type.FullName, " 中,属性 ", property.Name, " 不支持获取。")); if (setter == null) throw new Exception(TextGenerator.Merge("类 ", type.FullName, " 中,属性 ", property.Name, " 不支持设置。"));
// 类型兼容。
var pt = property.PropertyType; if (pt.Equals(typeof(byte[]).FullName)) ca.Type = ColumnType.Binary; else if (pt.Equals(typeof(Byte))) ca.Type = ColumnType.Integer; else if (pt.Equals(typeof(SByte))) ca.Type = ColumnType.Integer; else if (pt.Equals(typeof(Int16))) ca.Type = ColumnType.Integer; else if (pt.Equals(typeof(UInt16))) ca.Type = ColumnType.Integer; else if (pt.Equals(typeof(Int32))) ca.Type = ColumnType.Integer; else if (pt.Equals(typeof(UInt32))) ca.Type = ColumnType.Integer; else if (pt.Equals(typeof(Int64))) ca.Type = ColumnType.Integer; else if (pt.Equals(typeof(Single))) ca.Type = ColumnType.Float; else if (pt.Equals(typeof(Double))) ca.Type = ColumnType.Float; else if (pt.Equals(typeof(Decimal))) ca.Type = ColumnType.Float; else if (pt.Equals(typeof(DateTime))) ca.Type = ColumnType.DateTime; else if (pt.Equals(typeof(String))) { switch (ca.Type) { case ColumnType.Binary: case ColumnType.Integer: case ColumnType.Float: case ColumnType.DateTime: //throw new Exception(TextGenerator.Merge("类 ", type.FullName, " 中,属性 ", property.Name, " 的类型不受支持。"));
ca.Type = ColumnType.NText; break; } } else { ca.Type = ColumnType.NText; }
ca.Property = property;
// 锁定属性。
ca.Lock();
return ca; }
/// <summary>排序。</summary>
public static Dictionary<string, ColumnAttribute> SortColumns(Dictionary<string, ColumnAttribute> columns) { // if (type.BaseType.FullName.Equals(typeof(Record).FullName)) // 仅当使用基类时排序。
var sorted = new Dictionary<string, ColumnAttribute>();
if (columns.ContainsKey("Created")) sorted.Add("Created", columns["Created"]); if (columns.ContainsKey("Updated")) sorted.Add("Updated", columns["Updated"]); if (columns.ContainsKey("Flag")) sorted.Add("Flag", columns["Flag"]); if (columns.ContainsKey("Remark")) sorted.Add("Remark", columns["Remark"]); if (columns.ContainsKey("Key")) sorted.Add("Key", columns["Key"]);
foreach (var property in columns.Keys) { if (property == "Created") continue; if (property == "Updated") continue; if (property == "Flag") continue; if (property == "Remark") continue; if (property == "Key") continue;
sorted.Add(property, columns[property]); }
return sorted; }
/// <summary>限定表名称/列名称。</summary>
public static string RestrictName(string name, bool underline) { if (name == null || name == Constant.EmptyString) return Constant.EmptyString; var lower = name.ToLower(); var available = TextGenerator.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 (underline && !lower.StartsWith("_")) lower = TextGenerator.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; }
private static IDataParameter GenerateDataParameter(Record entity, ColumnAttribute attribute, CreateDataParameterCallback callback) { var property = attribute.Property; if (property == null) return null;
var getter = property.GetGetMethod(); if (getter == null) return null;
var parameter = null as IDataParameter; var value = getter.Invoke(entity, null);
//
if (attribute.Type == ColumnType.Binary || attribute.Type == ColumnType.Integer || attribute.Type == ColumnType.Float) { var temp = value; if (property.PropertyType.FullName == typeof(Decimal).FullName) { temp = TextUtility.GetDouble(temp.ToString()); } parameter = callback(new Parameter(attribute.Field, temp, attribute.Type, attribute.Length)); } else if (attribute.Type == ColumnType.DateTime) { parameter = callback(new Parameter(attribute.Field, value, attribute.Type, 0)); } else if (property.PropertyType.Equals(typeof(String))) { var text = value as string; if (text == null) text = ""; if (attribute.Length > 0) { switch (attribute.Type) { case ColumnType.VarChar: case ColumnType.NVarChar: text = TextUtility.RestrictLength(text, attribute.Length); break; case ColumnType.VarChar255: case ColumnType.NVarChar255: text = TextUtility.RestrictLength(text, 255); break; } } parameter = callback(new Parameter(attribute.Field, text, attribute.Type, attribute.Length)); } else { var text = (value == null) ? TextUtility.EmptyString : value.ToString(); parameter = callback(new Parameter(attribute.Field, text, attribute.Type, attribute.Length)); } return parameter; }
/// <summary>生成 IDataParameter 列表,用于 Insert 或 Update。</summary>
/// <exception cref="ArgumentNullException"></exception>
public List<IDataParameter> CreateDataParameters(Record entity, CreateDataParameterCallback callback, params string[] excluded) { if (entity == null) throw new ArgumentNullException(nameof(entity)); if (callback == null) throw new ArgumentNullException(nameof(excluded));
entity.FixProperties();
var list = new List<IDataParameter>(); foreach (var column in Columns) { var attribute = column.Value; if (ParseTable(entity.GetType()).Independent && attribute.Independent) continue;
var parameter = GenerateDataParameter(entity, attribute, callback); if (parameter == null) continue;
var add = true; foreach (var exclude in excluded) { var lower = parameter.ParameterName.ToLower(); if (lower == exclude.ToLower()) { add = false; } } if (add) list.Add(parameter); }
return list; }
#endregion
#region
/// <summary>获取 Record 根类中的属性名称。</summary>
private static List<string> GetRootProperties() { var list = new List<string>(); var type = typeof(Record); var properties = type.GetProperties(); foreach (var property in properties) { if (RuntimeUtility.ContainsAttribute<ColumnAttribute>(property, false)) { list.Add(property.Name); } } return list; }
#endregion
}
}
|