using Apewer.Internals; using System; using System.Collections.Generic; using System.Text; namespace Apewer.Source { /// <summary>数据库中的表。</summary> /// <remarks> /// <para>Name: 数据库的表名。</para> /// <para>Store: 数据存储区名称。</para> /// </remarks> [Serializable] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = true)] public sealed class TableAttribute : Attribute { #region 主要 private string _name = null; private string _store = null; private Type _model = null; private bool _primarykey = false; /// <summary>标记表属性。</summary> public TableAttribute(string name = null, string store = null) { _name = name.ToTrim(); _store = store.ToTrim(); } /// <summary>表名。</summary> public string Name { get => _name; } /// <summary>存储名。</summary> public string Store { get => _store; } /// <summary>使用此特性的类型。</summary> public Type Model { get => _model; } /// <summary>模型实现了 <see cref="IRecordPrimaryKey"/> 接口。</summary> public bool PrimaryKey { get => _primarykey; } /// <summary>从 <see cref="TableAttribute"/> 到 Boolean 的隐式转换,判断 <see cref="TableAttribute"/> 有效。</summary> public static implicit operator bool(TableAttribute instance) { if (instance == null) return false; if (instance._name.IsEmpty()) return false; return true; } #endregion #region 可修改特性 /// <summary>表的说明信息。(需要数据库客户端支持)</summary> public string Description { get; set; } /// <summary>独立结构,不依赖 Record 公共属性。</summary> internal bool Independent { get; set; } /// <summary>使用模型的所有属性,对缺少 Column 特性的属性使用默认参数的 Column 特性。</summary> public bool AllProperties { get; set; } #endregion #region cache private static Dictionary<string, TableAttribute> _tac = new Dictionary<string, TableAttribute>(); private static Type InterfacePrimaryKey = typeof(IRecordPrimaryKey); /// <summary>解析表特性,默认使用缓存以提升性能。</summary> public static TableAttribute Parse<T>(bool useCache = true) where T : class, new() => Parse(typeof(T), useCache); /// <summary>解析表特性,默认使用缓存以提升性能。</summary> public static TableAttribute Parse(Type type, bool useCache = true, bool force = false) { if (type == null) return null; 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; } if (!type.IsClass) return null; if (type.IsAbstract) return null; // throw new Exception($"类型 {type.FullName} 不包含 {typeof(TableAttribute).FullName}。"); var tas = type.GetCustomAttributes(typeof(TableAttribute), false); var ta = null as TableAttribute; var exists = tas.Length > 0; if (exists) ta = (TableAttribute)tas[0]; else { if (!force) return null; ta = new TableAttribute(); ta.AllProperties = true; ta.Independent = true; } ta._model = type; if (string.IsNullOrEmpty(ta.Name)) ta._name = type.Name; ta.Independent = RuntimeUtility.Contains<IndependentAttribute>(type, true); ta._primarykey = RuntimeUtility.IsInherits(type, InterfacePrimaryKey); if (useCache) { lock (_tac) { if (!_tac.ContainsKey(cacheKey)) _tac.Add(cacheKey, ta); } } return ta; } #endregion } }