using Apewer.Internals; using System; using System.Collections.Generic; using System.Reflection; using System.Text; namespace Apewer.Source { /// 数据库中的列,类型默认为 NVarChar(191),错误类型将修正为默认类型。 /// 注意:当一个数据模型中存在多个相同的 Field 时,将只有第一个被保留。 [Serializable] [AttributeUsage(AttributeTargets.Property, AllowMultiple = false, Inherited = true)] public sealed class ColumnAttribute : Attribute, IToJson { private PropertyInfo _property = null; internal string PropertyName = null; private string _field = null; private int _length = 0; private ColumnType _type; private bool _incremental = false; private bool _primarykey = false; private bool _noupdate = false; private bool _independent = false; private bool _valid = true; private bool _nullable = false; private void Init(string field, ColumnType type, int length) { _field = field; _type = type; switch (type) { case ColumnType.VarChar: case ColumnType.NVarChar: _length = length < 1 ? 191 : length; break; case ColumnType.VarChar191: case ColumnType.NVarChar191: _length = 191; break; default: _length = length; break; } } /// 使用自动的列名称。当类型为 VarChar 或 NVarChar 时必须指定长度。 /// public ColumnAttribute(ColumnType type = ColumnType.NVarChar191, int length = 191) => Init(null, type, length); /// 使用指定的列名称。当类型为 VarChar 或 NVarChar 时必须指定长度。 /// public ColumnAttribute(string field, ColumnType type = ColumnType.NVarChar191, int length = 191) => Init(field, type, length); /// 字段名。 public string Field { get => _field; } /// 指定字段的最大长度。 public int Length { get => _length; } /// 字段类型。 public ColumnType Type { get => _type; } #region 附加 /// 此特性有效。 public bool Valid { get => _valid; } /// 此列不被管理,Insert、Update 和 Create Table 将忽略此列。 public bool Independent { get => _independent; } /// 使用此特性的属性。 public PropertyInfo Property { get => _property; } /// 属性对应的字段是主键。 public bool PrimaryKey { get => _primarykey; } /// 属性对应的字段是自动增长的整数。 public bool Incremental { get => _incremental; } /// 属性可为 NULL 值。 public bool Nullable { get => _nullable; } /// 在执行 ORM 的 Update 方法时,不包含此属性。 public bool NoUpdate { get => _noupdate; } #endregion /// 生成 Json 对象。 public Json ToJson() { var json = Json.NewObject(); json.SetProperty("field", _field); json.SetProperty("type", _type.ToString()); json.SetProperty("length", _length); if (_property != null) { var property = Json.NewObject(); property.SetProperty("name", _property.Name); property.SetProperty("type", _property.PropertyType.FullName); json.SetProperty("property", property); json.SetProperty("nullable", _nullable); json.SetProperty("valid", _valid); json.SetProperty("independent", _independent); json.SetProperty("primarykey", _primarykey); json.SetProperty("incremental", _incremental); } return json; } /// 到 Boolean 的隐式转换,判断 有效。 public static implicit operator bool(ColumnAttribute instance) => instance != null; /// 解析列特性。 /// 注意:此方法不再抛出异常,当不存在正确的列特性时将返回 NULL 值 public static ColumnAttribute Parse(PropertyInfo property, bool force = false) { if (property == null) return null; // 属性带有 Independent 特性。 if (property.Contains()) return null; // 检查 ColumnAttribute。 ColumnAttribute ca; { var cas = property.GetCustomAttributes(typeof(ColumnAttribute), false); if (cas.LongLength < 1L) { if (!force) return null; ca = new ColumnAttribute(); } else ca = (ColumnAttribute)cas[0]; } // 检查属性方法。 var getter = property.GetGetMethod(false); var setter = property.GetSetMethod(false); if (getter == null || getter.IsStatic) return null; if (setter == null || setter.IsStatic) return null; // 检查主键特性和自增特性。 var pt = property.PropertyType; if (!ca._incremental && RuntimeUtility.Contains(property)) { if (pt.Equals(typeof(int)) || pt.Equals(typeof(long))) ca._incremental = true; } if (!ca._primarykey && RuntimeUtility.Contains(property)) ca._primarykey = true; // 检查免更新特性。 var nu = RuntimeUtility.GetAttribute(property, false); if (nu) ca._noupdate = true; // 检查列名称。 if (TextUtility.IsBlank(ca.Field)) ca._field = property.Name; // 类型兼容。 if (pt.Equals(typeof(byte[]))) ca._type = ColumnType.Bytes; else if (pt.Equals(typeof(bool))) ca._type = ColumnType.Boolean; 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.Bytes: case ColumnType.Integer: case ColumnType.Float: case ColumnType.DateTime: //throw new Exception(TextGenerator.Merge("类 ", type.FullName, " 中,属性 ", property.Name, " 的类型不受支持。")); ca._type = ColumnType.NVarChar; ca._length = 191; break; } } #if !NET20 else if (pt.Equals(typeof(Nullable))) { ca._type = ColumnType.Boolean; ca._nullable = true; } else if (pt.Equals(typeof(Nullable))) { ca._type = ColumnType.Integer; ca._nullable = true; } else if (pt.Equals(typeof(Nullable))) { ca._type = ColumnType.Integer; ca._nullable = true; } else if (pt.Equals(typeof(Nullable))) { ca._type = ColumnType.Integer; ca._nullable = true; } else if (pt.Equals(typeof(Nullable))) { ca._type = ColumnType.Integer; ca._nullable = true; } else if (pt.Equals(typeof(Nullable))) { ca._type = ColumnType.Integer; ca._nullable = true; } else if (pt.Equals(typeof(Nullable))) { ca._type = ColumnType.Integer; ca._nullable = true; } else if (pt.Equals(typeof(Nullable))) { ca._type = ColumnType.Integer; ca._nullable = true; } else if (pt.Equals(typeof(Nullable))) { ca._type = ColumnType.Float; ca._nullable = true; } else if (pt.Equals(typeof(Nullable))) { ca._type = ColumnType.Float; ca._nullable = true; } else if (pt.Equals(typeof(Nullable))) { ca._type = ColumnType.Float; ca._nullable = true; } else if (pt.Equals(typeof(Nullable))) { ca._type = ColumnType.DateTime; ca._nullable = true; } #endif else { ca._type = ColumnType.NVarChar191; ca._length = 191; } ca._property = property; ca.PropertyName = property.Name; return ca; } /// 对列特性排序,Key 和 Flag 将始终排在前部。 public static ColumnAttribute[] Sort(ColumnAttribute[] columns, bool sort = false) { var total = columns.Length; var key = null as ColumnAttribute; var flag = null as ColumnAttribute; var temp = new List(total); for (var i = 0; i < total; i++) { var ca = columns[i]; if (ca == null) continue; var pn = ca.Property.Name; if (pn == "Key") key = ca; else if (pn == "Flag") flag = ca; else temp.Add(ca); } if (sort && temp.Count > 0) temp.Sort((a, b) => a._field.CompareTo(b._field)); if (key == null && flag == null) return temp.ToArray(); total = 0; if (key != null) total += 1; if (flag != null) total += 1; total += temp.Count; var sorted = new List(total); if (key != null) sorted.Add(key); if (flag != null) sorted.Add(flag); sorted.AddRange(temp); return sorted.ToArray(); } internal void SetPrimaryKey() => _primarykey = true; } }