You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

148 lines
4.8 KiB

5 years ago
4 years ago
5 years ago
4 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
4 years ago
4 years ago
4 years ago
5 years ago
4 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
  1. using Apewer.Internals;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Text;
  5. namespace Apewer.Source
  6. {
  7. /// <summary>数据库中的表。</summary>
  8. /// <remarks>
  9. /// <para>Name: 数据库的表名。</para>
  10. /// <para>Store: 数据存储区名称。</para>
  11. /// </remarks>
  12. [Serializable]
  13. [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = true)]
  14. public sealed class TableAttribute : Attribute
  15. {
  16. #region 主要
  17. private string _name = null;
  18. private string _store = null;
  19. private Type _model = null;
  20. private bool _primarykey = false;
  21. /// <summary>标记表属性。</summary>
  22. public TableAttribute(string name = null, string store = null)
  23. {
  24. _name = name.ToTrim();
  25. _store = store.ToTrim();
  26. }
  27. /// <summary>表名。</summary>
  28. public string Name { get => _name; }
  29. /// <summary>存储名。</summary>
  30. public string Store { get => _store; }
  31. /// <summary>使用此特性的类型。</summary>
  32. public Type Model { get => _model; }
  33. /// <summary>模型实现了 <see cref="IRecordPrimaryKey"/> 接口。</summary>
  34. public bool PrimaryKey { get => _primarykey; }
  35. /// <summary>从 <see cref="TableAttribute"/> 到 Boolean 的隐式转换,判断 <see cref="TableAttribute"/> 有效。</summary>
  36. public static implicit operator bool(TableAttribute instance)
  37. {
  38. if (instance == null) return false;
  39. if (instance._name.IsEmpty()) return false;
  40. return true;
  41. }
  42. #endregion
  43. #region 可修改特性
  44. /// <summary>表的说明信息。(需要数据库客户端支持)</summary>
  45. public string Description { get; set; }
  46. /// <summary>独立结构,不依赖 Record 公共属性。</summary>
  47. internal bool Independent { get; set; }
  48. /// <summary>使用模型的所有属性,对缺少 Column 特性的属性使用默认参数的 Column 特性。</summary>
  49. public bool AllProperties { get; set; }
  50. #endregion
  51. #region 自定义
  52. /// <summary>根据类型自定义表名。</summary>
  53. public static Func<Type, string> CustomTableName { get; set; }
  54. #endregion
  55. #region cache
  56. private static Dictionary<string, TableAttribute> _tac = new Dictionary<string, TableAttribute>();
  57. private static Type InterfacePrimaryKey = typeof(IRecordPrimaryKey);
  58. /// <summary>解析表特性,默认使用缓存以提升性能。</summary>
  59. public static TableAttribute Parse<T>(bool useCache = true) where T : class, new() => Parse(typeof(T), useCache);
  60. /// <summary>解析表特性,默认使用缓存以提升性能。</summary>
  61. public static TableAttribute Parse(Type type, bool useCache = true, bool force = false)
  62. {
  63. if (type == null) return null;
  64. var cacheKey = type.FullName;
  65. if (useCache)
  66. {
  67. var hint = null as TableAttribute;
  68. lock (_tac)
  69. {
  70. if (_tac.ContainsKey(cacheKey)) hint = _tac[cacheKey];
  71. }
  72. if (hint != null) return hint;
  73. }
  74. if (!type.IsClass) return null;
  75. if (type.IsAbstract) return null;
  76. // throw new Exception($"类型 {type.FullName} 不包含 {typeof(TableAttribute).FullName}。");
  77. var tas = type.GetCustomAttributes(typeof(TableAttribute), false);
  78. var ta = null as TableAttribute;
  79. var exists = tas.Length > 0;
  80. if (exists) ta = (TableAttribute)tas[0];
  81. else
  82. {
  83. if (!force) return null;
  84. ta = new TableAttribute();
  85. ta.AllProperties = true;
  86. ta.Independent = true;
  87. }
  88. ta._model = type;
  89. if (string.IsNullOrEmpty(ta.Name))
  90. {
  91. if (CustomTableName == null)
  92. {
  93. ta._name = type.Name;
  94. }
  95. else
  96. {
  97. ta._name = CustomTableName.Invoke(type);
  98. if (string.IsNullOrEmpty(ta._name)) throw new ArgumentException($"CustomTableName 未返回类型 {type.Name} 的表名。");
  99. }
  100. }
  101. ta.Independent = RuntimeUtility.Contains<IndependentAttribute>(type, true);
  102. ta._primarykey = RuntimeUtility.IsInherits(type, InterfacePrimaryKey);
  103. if (useCache)
  104. {
  105. lock (_tac)
  106. {
  107. if (!_tac.ContainsKey(cacheKey)) _tac.Add(cacheKey, ta);
  108. }
  109. }
  110. return ta;
  111. }
  112. #endregion
  113. }
  114. }