放弃所有标记为不再使用的代码,为新版本扫干净道路
nnhy 编写于 2016-02-13 21:25:33
X
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Reflection;
using XCode.DataAccessLayer;
using System.Linq;

namespace XCode.Configuration
{
    /// <summary>数据属性元数据以及特性</summary>
    public class FieldItem
    {
        #region 属性
        /// <summary>属性元数据</summary>
        internal PropertyInfo _Property;

        /// <summary>绑定列特性</summary>
        private BindColumnAttribute _Column;

        /// <summary>数据字段特性</summary>
        private DataObjectFieldAttribute _DataObjectField;

        private DescriptionAttribute _Description;

        private DisplayNameAttribute _DisplayName;

        private String _des;
        /// <summary>备注</summary>
        public String Description { get { return _des; } internal set { _des = value; } }

        private String _dis;
        /// <summary>说明</summary>
        public String DisplayName
        {
            get
            {
                if (!string.IsNullOrEmpty(_dis)) return _dis;
                var name = Description;
                if (String.IsNullOrEmpty(name)) return Name;

                var p = name.IndexOf("。");
                if (p > 0) name = name.Substring(0, p);

                return name;
            }
            internal set { _dis = value; }
        }

        /// <summary>顺序标识</summary>
        internal Int32 _ID;
        #endregion

        #region 扩展属性
        private String _Name;
        /// <summary>属性名</summary>
        public String Name { get { return _Name; } internal set { _Name = value; } }

        private Type _Type;
        /// <summary>属性类型</summary>
        public Type Type { get { return _Type; } internal set { _Type = value; } }

        private Type _DeclaringType;
        /// <summary>声明类型</summary>
        internal Type DeclaringType
        {
            get
            {
                if (_DeclaringType != null) { return _DeclaringType; }
                // 确保动态增加的数据字段得到实体类型
                return Table.EntityType;
            }
            set { _DeclaringType = value; }
        }

        private Boolean _IsIdentity;
        /// <summary>是否标识列</summary>
        public Boolean IsIdentity { get { return _IsIdentity; } internal set { _IsIdentity = value; } }

        private Boolean _PrimaryKey;
        /// <summary>是否主键</summary>
        public Boolean PrimaryKey { get { return _PrimaryKey; } internal set { _PrimaryKey = value; } }

        private Boolean _Master;
        /// <summary>是否主字段。主字段作为业务主要字段,代表当前数据行意义</summary>
        public Boolean Master { get { return _Master; } private set { _Master = value; } }

        private Boolean _IsNullable;
        /// <summary>是否允许空</summary>
        public Boolean IsNullable { get { return _IsNullable; } internal set { _IsNullable = value; } }

        private Int32 _Length;
        /// <summary>长度</summary>
        public Int32 Length { get { return _Length; } internal set { _Length = value; } }

        private Boolean _IsDataObjectField;
        /// <summary>是否数据绑定列</summary>
        public Boolean IsDataObjectField { get { return _IsDataObjectField; } set { _IsDataObjectField = value; } }

        /// <summary>是否动态字段</summary>
        public Boolean IsDynamic { get { return _Property == null; } }

        ///// <summary>显示名。如果备注不为空则采用备注,否则采用属性名</summary>
        //public String DisplayName
        //{
        //    get
        //    {
        //        var name = Description;
        //        if (String.IsNullOrEmpty(name)) return Name;

        //        var p = name.IndexOf("。");
        //        if (p > 0) name = name.Substring(0, p);

        //        return name;
        //    }
        //}

        /// <summary>字段名要过滤掉的标识符,考虑MSSQL、MySql、SQLite、Oracle等</summary>
        static Char[] COLUMNNAME_FLAG = new Char[] { '[', ']', '\'', '"', '`' };

        private String _ColumnName;
        /// <summary>用于数据绑定的字段名</summary>
        /// <remarks>
        /// 默认使用BindColumn特性中指定的字段名,如果没有指定,则使用属性名。
        /// 字段名可能两边带有方括号等标识符
        /// </remarks>
        public String ColumnName { get { return _ColumnName; } set { if (value != null) _ColumnName = value.Trim(COLUMNNAME_FLAG); } }

        private String _DefaultValue;
        /// <summary>默认值</summary>
        public String DefaultValue { get { return _DefaultValue; } internal set { _DefaultValue = value; } }

        private Boolean _ReadOnly;
        /// <summary>是否只读</summary>
        /// <remarks>set { _ReadOnly = value; } 放出只读属性的设置,比如在编辑页面的时候,有的字段不能修改 如修改用户时  不能修改用户名</remarks>
        public Boolean ReadOnly { get { return _ReadOnly; }set { _ReadOnly = value; } }

        internal TableItem _Table;
        /// <summary>表</summary>
        public TableItem Table { get { return _Table; } }

        private IDataColumn _Field;
        /// <summary>字段</summary>
        public IDataColumn Field { get { return _Field; } }

        /// <summary>实体操作者</summary>
        public IEntityOperate Factory
        {
            get
            {
                Type type = Table.EntityType;
                if (type.IsInterface) return null;

                return EntityFactory.CreateOperate(type);
            }
        }

        /// <summary>已格式化的字段名,可字节用于SQL中。主要用于处理关键字,比如MSSQL里面的[User]</summary>
        public String FormatedName { get { return Factory.FormatName(ColumnName); } }

        /// <summary>跟当前字段有关系的原始字段</summary>
        public FieldItem OriField { get; internal set; }

        /// <summary>宽度</summary>
        /// <remarks>主要用于界面上的控件宽度</remarks>
        public int Width { get; set; }

        /// <summary>排序</summary>
        /// <remarks>主要用于界面上的控件显示排序</remarks>
        public int Sort { get; set; }


        /// <summary>跟当前字段有关系的原始字段</summary>
        /// <remarks>(原始字段,主要是在列表或者是Form里替换字段后可以读取原来的绑定关系),不敢用OriField,因为暂时没有去查OriField具体的用途。</remarks>
        public FieldItem OldField { get;  set; }
        #endregion

        #region 构造
        internal FieldItem() { }

        /// <summary>构造函数</summary>
        /// <param name="table"></param>
        /// <param name="property">属性</param>
        public FieldItem(TableItem table, PropertyInfo property)
        {
            //if (property == null) throw new ArgumentNullException("property");

            _Table = table;

            if (property != null)
            {
                _Property = property;
                var dc = _Column = BindColumnAttribute.GetCustomAttribute(property);
                var df = _DataObjectField = property.GetCustomAttribute<DataObjectFieldAttribute>();
                var ds = _Description = property.GetCustomAttribute<DescriptionAttribute>();
                var di = _DisplayName = property.GetCustomAttribute<DisplayNameAttribute>();
                Name = property.Name;
                Type = property.PropertyType;
                DeclaringType = property.DeclaringType;

                if (df != null)
                {
                    IsIdentity = df.IsIdentity;
                    PrimaryKey = df.PrimaryKey;
                    IsNullable = df.IsNullable;
                    Length = df.Length;

                    IsDataObjectField = true;
                }

                if (dc != null)
                {
                    _ID = dc.Order;
                    Master = dc.Master;
                }

                if (dc != null && !dc.Name.IsNullOrWhiteSpace())
                    ColumnName = dc.Name;
                else
                    ColumnName = Name;

                if (ds != null && !String.IsNullOrEmpty(ds.Description))
                    Description = ds.Description;
                else if (dc != null && !String.IsNullOrEmpty(dc.Description))
                    Description = dc.Description;
                if (di != null && !di.DisplayName.IsNullOrEmpty())
                    DisplayName = di.DisplayName;

                _ReadOnly = !property.CanWrite;
                var ra = property.GetCustomAttribute<ReadOnlyAttribute>();
                if (ra != null) _ReadOnly = ra.IsReadOnly;
            }
        }
        #endregion

        #region 方法
        /// <summary>已重载。</summary>
        /// <returns></returns>
        public override string ToString()
        {
            // 为了保持兼容旧的_.Name等代码,必须只能返回字段名
            return ColumnName;
        }

        /// <summary>填充到XField中去</summary>
        /// <param name="field">字段</param>
        public void Fill(IDataColumn field)
        {
            _Field = field;

            if (field == null) return;

            IDataColumn dc = field;
            if (dc == null) return;

            dc.ID = _ID;
            dc.ColumnName = ColumnName;
            dc.Name = Name;
            dc.DataType = Type;
            dc.Description = Description;
            dc.Default = DefaultValue;

            var col = _Column;
            if (col != null)
            {
                dc.RawType = col.RawType;
                dc.Precision = col.Precision;
                dc.Scale = col.Scale;
                dc.IsUnicode = col.IsUnicode;
            }
            else
            {
                dc.IsUnicode = true;
            }

            // 特别处理,兼容旧版本
            if (dc.DataType == typeof(Decimal))
            {
                if (dc.Precision == 0) dc.Precision = 18;
            }

            dc.Length = Length;
            dc.Identity = IsIdentity;
            dc.PrimaryKey = PrimaryKey;
            dc.Nullable = IsNullable;
            dc.Master = Master;
        }

        /// <summary>建立表达式</summary>
        /// <param name="action"></param>
        /// <param name="value">数值</param>
        /// <returns></returns>
        internal Expression CreateFormatExpression(String action, String value) { return new FormatExpression(this, action, value); }

        internal static Expression CreateFieldExpression(FieldItem field, String action, Object value)
        {
            return field == null ? new Expression() : new FieldExpression(field, action, value);
        }
        #endregion

        #region 基本运算
        /// <summary>等于</summary>
        /// <param name="value">数值</param>
        /// <returns></returns>
        public Expression Equal(object value) { return CreateFieldExpression(this, "=", value); }

        /// <summary>不等于</summary>
        /// <param name="value">数值</param>
        /// <returns></returns>
        public Expression NotEqual(object value) { return CreateFieldExpression(this, "<>", value); }

        Expression CreateLike(String value) { return CreateFormatExpression("{0} Like {1}", Factory.FormatValue(this, value)); }

        /// <summary>以某个字符串开始,{0}%操作</summary>
        /// <remarks>空参数不参与表达式操作,不生成该部分SQL拼接</remarks>
        /// <param name="value">数值</param>
        /// <returns></returns>
        public Expression StartsWith(String value)
        {
            if (value == null || value + "" == "") return new Expression();

            return CreateLike("{0}%".F(value));
        }

        /// <summary>以某个字符串结束,%{0}操作</summary>
        /// <remarks>空参数不参与表达式操作,不生成该部分SQL拼接</remarks>
        /// <param name="value">数值</param>
        /// <returns></returns>
        public Expression EndsWith(String value)
        {
            if (value == null || value + "" == "") return new Expression();

            return CreateLike("%{0}".F(value));
        }

        /// <summary>包含某个字符串,%{0}%操作</summary>
        /// <remarks>空参数不参与表达式操作,不生成该部分SQL拼接</remarks>
        /// <param name="value">数值</param>
        /// <returns></returns>
        public Expression Contains(String value)
        {
            if (value == null || value + "" == "") return new Expression();

            return CreateLike("%{0}%".F(value));
        }

        ///// <summary>In操作。直接使用字符串可能有注入风险</summary>
        ///// <remarks>空参数不参与表达式操作,不生成该部分SQL拼接</remarks>
        ///// <param name="value">逗号分割的数据。可能有注入风险</param>
        ///// <returns></returns>
        //[Obsolete("=>In(IEnumerable value),直接使用字符串参数可能有注入风险")]
        //public Expression In(String value)
        //{
        //    if (String.IsNullOrEmpty(value)) return new Expression();

        //    return CreateFormatExpression("{0} In({1})", Factory.FormatValue(this, value));
        //}

        /// <summary>In操作</summary>
        /// <remarks>空参数不参与表达式操作,不生成该部分SQL拼接。只有一项时转为等于</remarks>
        /// <param name="value">枚举数据,会转化为字符串</param>
        /// <returns></returns>
        public Expression In(IEnumerable value) { return _In(value, true); }

        Expression _In(IEnumerable value, Boolean flag)
        {
            if (value == null) return new Expression();

            var op = Factory;
            var name = op.FormatName(ColumnName);

            var vs = new List<Object>();
            var list = new List<String>();
            foreach (var item in value)
            {
                // 避免重复项
                if (vs.Contains(item)) continue;
                vs.Add(item);

                // 格式化数值
                var str = op.FormatValue(this, item);
                list.Add(str);
            }
            if (list.Count <= 0) return new Expression();

            // 特殊处理枚举全选,如果全选了枚举的所有项,则跳过当前条件构造
            if (vs[0].GetType().IsEnum)
            {
                var es = Enum.GetValues(vs[0].GetType());
                if (es.Length == vs.Count)
                {
                    if (vs.SequenceEqual(es.Cast<Object>())) return new Expression();
                }
            }

            // 如果In操作且只有一项,修改为等于
            if (list.Count == 1) return CreateFieldExpression(this, flag ? "=" : "<>", vs[0]);

            return CreateFormatExpression(flag ? "{0} In({1})" : "{0} Not In({1})", list.Join(","));
        }

        ///// <summary>NotIn操作。直接使用字符串可能有注入风险</summary>
        ///// <remarks>空参数不参与表达式操作,不生成该部分SQL拼接</remarks>
        ///// <param name="value">数值</param>
        ///// <returns></returns>
        //[Obsolete("=>NotIn(IEnumerable value),直接使用字符串参数可能有注入风险")]
        //public Expression NotIn(String value)
        //{
        //    if (String.IsNullOrEmpty(value)) return new Expression();

        //    return CreateFormatExpression("{0} Not In({1})", Factory.FormatValue(this, value));
        //}

        /// <summary>NotIn操作</summary>
        /// <remarks>空参数不参与表达式操作,不生成该部分SQL拼接。只有一项时修改为不等于</remarks>
        /// <param name="value">数值</param>
        /// <returns></returns>
        public Expression NotIn(IEnumerable value) { return _In(value, false); }

        /// <summary>In操作。直接使用字符串可能有注入风险</summary>
        /// <remarks>空参数不参与表达式操作,不生成该部分SQL拼接</remarks>
        /// <param name="builder">逗号分割的数据。可能有注入风险</param>
        /// <returns></returns>
        public Expression In(SelectBuilder builder)
        {
            if (builder == null) return new Expression();

            return CreateFormatExpression("{0} In({1})", builder);
        }

        /// <summary>NotIn操作。直接使用字符串可能有注入风险</summary>
        /// <remarks>空参数不参与表达式操作,不生成该部分SQL拼接</remarks>
        /// <param name="builder">数值</param>
        /// <returns></returns>
        public Expression NotIn(SelectBuilder builder)
        {
            if (builder == null) return new Expression();

            return CreateFormatExpression("{0} NotIn({1})", builder);
        }

        /// <summary>IsNull操作,不为空,一般用于字符串,但不匹配0长度字符串</summary>
        /// <returns></returns>
        public Expression IsNull() { return CreateFormatExpression("{0} Is Null", null); }

        /// <summary>NotIn操作</summary>
        /// <returns></returns>
        public Expression NotIsNull() { return CreateFormatExpression("Not {0} Is Null", null); }
        #endregion

        #region 复杂运算
        /// <summary>IsNullOrEmpty操作,用于空或者0长度字符串</summary>
        /// <returns></returns>
        public Expression IsNullOrEmpty() { return IsNull() | Equal(""); }

        /// <summary>NotIsNullOrEmpty操作</summary>
        /// <returns></returns>
        public Expression NotIsNullOrEmpty() { return NotIsNull() & NotEqual(""); }

        /// <summary>是否True或者False/Null,参数决定两组之一</summary>
        /// <param name="flag"></param>
        /// <returns></returns>
        public Expression IsTrue(Boolean? flag)
        {
            if (flag == null) return null;

            var f = flag.Value;
            if (f) return Equal(true);

            if (this.Type == typeof(Boolean) && !IsNullable) return Equal(false);

            return NotEqual(true) | IsNull();
        }

        /// <summary>是否False或者True/Null,参数决定两组之一</summary>
        /// <param name="flag"></param>
        /// <returns></returns>
        public Expression IsFalse(Boolean? flag)
        {
            if (flag == null) return null;

            var f = flag.Value;
            if (!f) return Equal(false);

            if (this.Type == typeof(Boolean) && !IsNullable) return Equal(true);

            return NotEqual(false) | IsNull();
        }

        /// <summary>时间专用区间函数</summary>
        /// <param name="start">起始时间,大于等于</param>
        /// <param name="end">结束时间,小于。如果是日期,则加一天</param>
        /// <returns></returns>
        public Expression Between(DateTime start, DateTime end)
        {
            if (start <= DateTime.MinValue)
            {
                if (end <= DateTime.MinValue) return null;

                // 如果只有日期,则加一天,表示包含这一天
                if (end == end.Date) end = end.AddDays(1);

                return this < end;
            }
            else
            {
                var exp = this >= start;
                if (end <= DateTime.MinValue) return exp;

                // 如果只有日期,则加一天,表示包含这一天
                if (end == end.Date) end = end.AddDays(1);

                return exp & this < end;
            }
        }
        #endregion

        #region 重载运算符
        /// <summary>大于</summary>
        /// <param name="field">字段</param>
        /// <param name="value">数值</param>
        /// <returns></returns>
        public static Expression operator >(FieldItem field, Object value) { return CreateFieldExpression(field, ">", value); }

        /// <summary>小于</summary>
        /// <param name="field">字段</param>
        /// <param name="value">数值</param>
        /// <returns></returns>
        public static Expression operator <(FieldItem field, Object value) { return CreateFieldExpression(field, "<", value); }

        /// <summary>大于等于</summary>
        /// <param name="field">字段</param>
        /// <param name="value">数值</param>
        /// <returns></returns>
        public static Expression operator >=(FieldItem field, Object value) { return CreateFieldExpression(field, ">=", value); }

        /// <summary>小于等于</summary>
        /// <param name="field">字段</param>
        /// <param name="value">数值</param>
        /// <returns></returns>
        public static Expression operator <=(FieldItem field, Object value) { return CreateFieldExpression(field, "<=", value); }
        #endregion

        #region 类型转换
        /// <summary>类型转换</summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static implicit operator String(FieldItem obj)
        {
            return !obj.Equals(null) ? obj.ColumnName : null;
        }
        #endregion
    }

    /// <summary>继承FieldItem,仅仅为了重载==和!=运算符</summary>
    [EditorBrowsable(EditorBrowsableState.Never)]
    public class Field : FieldItem
    {
        #region 构造
        /// <summary>构造函数</summary>
        /// <param name="table"></param>
        /// <param name="property">属性</param>
        public Field(TableItem table, PropertyInfo property) : base(table, property) { }

        internal Field(TableItem table, String name, Type type, String description, Int32 length)
        {
            _Table = table;

            _ID = table.Fields.Length + 1;

            Name = name;
            ColumnName = name;
            Type = type;
            Description = description;
            Length = length;

            IsNullable = true;
        }
        #endregion

        /// <summary>等于</summary>
        /// <param name="field">字段</param>
        /// <param name="value">数值</param>
        /// <returns></returns>
        public static Expression operator ==(Field field, Object value) { return field.Equal(value); }

        /// <summary>不等于</summary>
        /// <param name="field">字段</param>
        /// <param name="value">数值</param>
        /// <returns></returns>
        public static Expression operator !=(Field field, Object value) { return field.NotEqual(value); }

        /// <summary>重写一下</summary>
        /// <returns></returns>
        public override int GetHashCode() { return base.GetHashCode(); }

        /// <summary>重写一下</summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public override bool Equals(object obj) { return base.Equals(obj); }

        #region 类型转换
        /// <summary>类型转换</summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static implicit operator String(Field obj)
        {
            return !obj.Equals(null) ? obj.ColumnName : null;
        }
        #endregion
    }
}