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
{
private PropertyInfo _property = null;
internal string PropertyName = null;
private string _field = "";
private int _length = 0;
private ColumnType _type;
private bool _independent = false;
private bool _valid = true;
private void Init(string field, ColumnType type, int length)
{
if (string.IsNullOrEmpty(field)) field = TableStructure.RestrictName(field, string.IsNullOrEmpty(field));
_field = string.IsNullOrEmpty(field) ? "" : TableStructure.RestrictName(field, string.IsNullOrEmpty(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; }
/// Independent 特性。
public bool Independent { get => _independent; }
/// 使用此特性的属性。
public PropertyInfo Property { get => _property; }
#endregion
/// 解析列特性。
/// 注意:此方法不再抛出异常,当不存在正确的列特性时将返回 NULL 值
public static ColumnAttribute Parse(Type type, PropertyInfo property, TableAttribute ta)
{
if (type == null || property == null || ta == null) return null;
// 属性带有 Independent 特性。
if (property.Contains()) return null;
// 检查 ColumnAttribute。
ColumnAttribute ca;
{
var cas = property.GetCustomAttributes(typeof(ColumnAttribute), false);
if (cas.LongLength < 1L)
{
if (!ta.AllProperties) 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;
// 检查列名称。
if (TextUtility.IsBlank(ca.Field)) ca._field = "_" + property.Name;
// 类型兼容。
var pt = property.PropertyType;
if (pt.Equals(typeof(byte[]).FullName)) ca._type = ColumnType.Bytes;
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;
}
}
else
{
ca._type = ColumnType.NVarChar191;
ca._length = 191;
}
ca._property = property;
ca.PropertyName = property.Name;
if (ca.PropertyName == "Key" || ca.PropertyName == "Flag") ca._independent = true;
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();
}
}
}