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.

252 lines
11 KiB

4 years ago
3 years ago
4 years ago
4 years ago
4 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
4 years ago
4 years ago
3 years ago
3 years ago
3 years ago
4 years ago
3 years ago
3 years ago
4 years ago
3 years ago
4 years ago
4 years ago
3 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 years ago
  1. using Apewer.Internals;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Reflection;
  5. using System.Text;
  6. namespace Apewer.Source
  7. {
  8. /// <summary>数据库中的列,类型默认为 NVarChar(191),错误类型将修正为默认类型。</summary>
  9. /// <remarks>注意:当一个数据模型中存在多个相同的 Field 时,将只有第一个被保留。</remarks>
  10. [Serializable]
  11. [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)]
  12. public sealed class ColumnAttribute : Attribute, IToJson
  13. {
  14. private PropertyInfo _property = null;
  15. internal string PropertyName = null;
  16. private string _field = null;
  17. private int _length = 0;
  18. private ColumnType _type;
  19. private bool _incremental = false;
  20. private bool _primarykey = false;
  21. private bool _noupdate = false;
  22. private bool _independent = false;
  23. private bool _valid = true;
  24. private bool _nullable = false;
  25. private void Init(string field, ColumnType type, int length)
  26. {
  27. _field = field;
  28. _type = type;
  29. switch (type)
  30. {
  31. case ColumnType.VarChar:
  32. case ColumnType.NVarChar:
  33. _length = length < 1 ? 191 : length;
  34. break;
  35. case ColumnType.VarChar191:
  36. case ColumnType.NVarChar191:
  37. _length = 191;
  38. break;
  39. default:
  40. _length = length;
  41. break;
  42. }
  43. }
  44. /// <summary>使用自动的列名称。当类型为 VarChar 或 NVarChar 时必须指定长度。</summary>
  45. /// <exception cref="System.ArgumentOutOfRangeException"></exception>
  46. public ColumnAttribute(ColumnType type = ColumnType.NVarChar191, int length = 191) => Init(null, type, length);
  47. /// <summary>使用指定的列名称。当类型为 VarChar 或 NVarChar 时必须指定长度。</summary>
  48. /// <exception cref="System.ArgumentOutOfRangeException"></exception>
  49. public ColumnAttribute(string field, ColumnType type = ColumnType.NVarChar191, int length = 191) => Init(field, type, length);
  50. /// <summary>字段名。</summary>
  51. public string Field { get => _field; }
  52. /// <summary>指定字段的最大长度。</summary>
  53. public int Length { get => _length; }
  54. /// <summary>字段类型。</summary>
  55. public ColumnType Type { get => _type; }
  56. #region 附加
  57. /// <summary>此特性有效。</summary>
  58. public bool Valid { get => _valid; }
  59. /// <summary>此列不被管理,Insert、Update 和 Create Table 将忽略此列。</summary>
  60. public bool Independent { get => _independent; }
  61. /// <summary>使用此特性的属性。</summary>
  62. public PropertyInfo Property { get => _property; }
  63. /// <summary>属性对应的字段是主键。</summary>
  64. public bool PrimaryKey { get => _primarykey; }
  65. /// <summary>属性对应的字段是自动增长的整数。</summary>
  66. public bool Incremental { get => _incremental; }
  67. /// <summary>属性可为 NULL 值。</summary>
  68. public bool Nullable { get => _nullable; }
  69. /// <summary>在执行 ORM 的 Update 方法时,不包含此属性。</summary>
  70. public bool NoUpdate { get => _noupdate; }
  71. #endregion
  72. /// <summary>生成 Json 对象。</summary>
  73. public Json ToJson()
  74. {
  75. var json = Json.NewObject();
  76. json.SetProperty("field", _field);
  77. json.SetProperty("type", _type.ToString());
  78. json.SetProperty("length", _length);
  79. if (_property != null)
  80. {
  81. var property = Json.NewObject();
  82. property.SetProperty("name", _property.Name);
  83. property.SetProperty("type", _property.PropertyType.FullName);
  84. json.SetProperty("property", property);
  85. json.SetProperty("nullable", _nullable);
  86. json.SetProperty("valid", _valid);
  87. json.SetProperty("independent", _independent);
  88. json.SetProperty("primarykey", _primarykey);
  89. json.SetProperty("incremental", _incremental);
  90. }
  91. return json;
  92. }
  93. /// <summary>从 <see cref="ColumnAttribute"/> 到 Boolean 的隐式转换,判断 <see cref="ColumnAttribute"/> 有效。</summary>
  94. public static implicit operator bool(ColumnAttribute instance) => instance != null;
  95. /// <summary>解析列特性。</summary>
  96. /// <remarks>注意:此方法不再抛出异常,当不存在正确的列特性时将返回 NULL 值</remarks>
  97. public static ColumnAttribute Parse(PropertyInfo property, bool force = false)
  98. {
  99. if (property == null) return null;
  100. // 属性带有 Independent 特性。
  101. if (property.Contains<IndependentAttribute>()) return null;
  102. // 检查 ColumnAttribute。
  103. ColumnAttribute ca;
  104. {
  105. var cas = property.GetCustomAttributes(typeof(ColumnAttribute), false);
  106. if (cas.LongLength < 1L)
  107. {
  108. if (!force) return null;
  109. ca = new ColumnAttribute();
  110. }
  111. else ca = (ColumnAttribute)cas[0];
  112. }
  113. // 检查属性方法。
  114. var getter = property.GetGetMethod(false);
  115. var setter = property.GetSetMethod(false);
  116. if (getter == null || getter.IsStatic) return null;
  117. if (setter == null || setter.IsStatic) return null;
  118. // 检查主键特性和自增特性。
  119. var pt = property.PropertyType;
  120. if (!ca._incremental && RuntimeUtility.Contains<IncrementalAttribute>(property))
  121. {
  122. if (pt.Equals(typeof(int)) || pt.Equals(typeof(long))) ca._incremental = true;
  123. }
  124. if (!ca._primarykey && RuntimeUtility.Contains<PrimaryKeyAttribute>(property)) ca._primarykey = true;
  125. // 检查免更新特性。
  126. var nu = RuntimeUtility.GetAttribute<NoUpdateAttribute>(property, false);
  127. if (nu) ca._noupdate = true;
  128. // 检查列名称。
  129. if (TextUtility.IsBlank(ca.Field)) ca._field = property.Name;
  130. // 类型兼容。
  131. if (pt.Equals(typeof(byte[]))) ca._type = ColumnType.Bytes;
  132. else if (pt.Equals(typeof(bool))) ca._type = ColumnType.Boolean;
  133. else if (pt.Equals(typeof(Byte))) ca._type = ColumnType.Integer;
  134. else if (pt.Equals(typeof(SByte))) ca._type = ColumnType.Integer;
  135. else if (pt.Equals(typeof(Int16))) ca._type = ColumnType.Integer;
  136. else if (pt.Equals(typeof(UInt16))) ca._type = ColumnType.Integer;
  137. else if (pt.Equals(typeof(Int32))) ca._type = ColumnType.Integer;
  138. else if (pt.Equals(typeof(UInt32))) ca._type = ColumnType.Integer;
  139. else if (pt.Equals(typeof(Int64))) ca._type = ColumnType.Integer;
  140. else if (pt.Equals(typeof(Single))) ca._type = ColumnType.Float;
  141. else if (pt.Equals(typeof(Double))) ca._type = ColumnType.Float;
  142. else if (pt.Equals(typeof(Decimal))) ca._type = ColumnType.Float;
  143. else if (pt.Equals(typeof(DateTime))) ca._type = ColumnType.DateTime;
  144. else if (pt.Equals(typeof(String)))
  145. {
  146. switch (ca.Type)
  147. {
  148. case ColumnType.Bytes:
  149. case ColumnType.Integer:
  150. case ColumnType.Float:
  151. case ColumnType.DateTime:
  152. //throw new Exception(TextGenerator.Merge("类 ", type.FullName, " 中,属性 ", property.Name, " 的类型不受支持。"));
  153. ca._type = ColumnType.NVarChar;
  154. ca._length = 191;
  155. break;
  156. }
  157. }
  158. #if !NET20
  159. else if (pt.Equals(typeof(Nullable<Boolean>))) { ca._type = ColumnType.Boolean; ca._nullable = true; }
  160. else if (pt.Equals(typeof(Nullable<Byte>))) { ca._type = ColumnType.Integer; ca._nullable = true; }
  161. else if (pt.Equals(typeof(Nullable<SByte>))) { ca._type = ColumnType.Integer; ca._nullable = true; }
  162. else if (pt.Equals(typeof(Nullable<Int16>))) { ca._type = ColumnType.Integer; ca._nullable = true; }
  163. else if (pt.Equals(typeof(Nullable<UInt16>))) { ca._type = ColumnType.Integer; ca._nullable = true; }
  164. else if (pt.Equals(typeof(Nullable<Int32>))) { ca._type = ColumnType.Integer; ca._nullable = true; }
  165. else if (pt.Equals(typeof(Nullable<UInt32>))) { ca._type = ColumnType.Integer; ca._nullable = true; }
  166. else if (pt.Equals(typeof(Nullable<Int64>))) { ca._type = ColumnType.Integer; ca._nullable = true; }
  167. else if (pt.Equals(typeof(Nullable<Single>))) { ca._type = ColumnType.Float; ca._nullable = true; }
  168. else if (pt.Equals(typeof(Nullable<Double>))) { ca._type = ColumnType.Float; ca._nullable = true; }
  169. else if (pt.Equals(typeof(Nullable<Decimal>))) { ca._type = ColumnType.Float; ca._nullable = true; }
  170. else if (pt.Equals(typeof(Nullable<DateTime>))) { ca._type = ColumnType.DateTime; ca._nullable = true; }
  171. #endif
  172. else
  173. {
  174. ca._type = ColumnType.NVarChar191;
  175. ca._length = 191;
  176. }
  177. ca._property = property;
  178. ca.PropertyName = property.Name;
  179. return ca;
  180. }
  181. /// <summary>对列特性排序,Key 和 Flag 将始终排在前部。</summary>
  182. public static ColumnAttribute[] Sort(ColumnAttribute[] columns, bool sort = false)
  183. {
  184. var total = columns.Length;
  185. var key = null as ColumnAttribute;
  186. var flag = null as ColumnAttribute;
  187. var temp = new List<ColumnAttribute>(total);
  188. for (var i = 0; i < total; i++)
  189. {
  190. var ca = columns[i];
  191. if (ca == null) continue;
  192. var pn = ca.Property.Name;
  193. if (pn == "Key") key = ca;
  194. else if (pn == "Flag") flag = ca;
  195. else temp.Add(ca);
  196. }
  197. if (sort && temp.Count > 0) temp.Sort((a, b) => a._field.CompareTo(b._field));
  198. if (key == null && flag == null) return temp.ToArray();
  199. total = 0;
  200. if (key != null) total += 1;
  201. if (flag != null) total += 1;
  202. total += temp.Count;
  203. var sorted = new List<ColumnAttribute>(total);
  204. if (key != null) sorted.Add(key);
  205. if (flag != null) sorted.Add(flag);
  206. sorted.AddRange(temp);
  207. return sorted.ToArray();
  208. }
  209. internal void SetPrimaryKey() => _primarykey = true;
  210. }
  211. }