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.

284 lines
12 KiB

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