v9.6.2017.0808   重构正向工程,基于映射表查找数据库字段类型到实体类型的映射
大石头 编写于 2017-08-08 21:38:06
X
using System;
using System.Collections;
using System.Collections.Generic;
using NewLife.Collections;
using NewLife.Reflection;

namespace XCode
{
    /// <summary>实体处理模块</summary>
    public interface IEntityModule
    {
        /// <summary>为指定实体类初始化模块,返回是否支持</summary>
        /// <param name="entityType"></param>
        /// <returns></returns>
        Boolean Init(Type entityType);

        /// <summary>创建实体对象</summary>
        /// <param name="entity"></param>
        /// <param name="forEdit"></param>
        void Create(IEntity entity, Boolean forEdit);

        /// <summary>验证实体对象</summary>
        /// <param name="entity"></param>
        /// <param name="isNew"></param>
        /// <returns></returns>
        Boolean Valid(IEntity entity, Boolean isNew);
    }

    /// <summary>实体模块集合</summary>
    public class EntityModules : ICollection<IEntityModule>
    {
        #region 属性
        /// <summary>实体类型</summary>
        public Type EntityType { get; set; }

        /// <summary>模块集合</summary>
        public List<IEntityModule> Modules { get; set; } = new List<IEntityModule>();
        #endregion

        #region 构造
        /// <summary>实例化实体模块集合</summary>
        /// <param name="entityType"></param>
        public EntityModules(Type entityType)
        {
            EntityType = entityType;

            //// 异步扫描添加,避免阻塞
            //var task = Task.Run(() =>
            //{
            //    foreach (var item in typeof(IEntityModule).GetAllSubclasses(true))
            //    {
            //        var module = item.CreateInstance() as IEntityModule;
            //        Add(module);
            //    }
            //});

            //// 略微等一下
            //task.Wait(100);
        }
        #endregion

        #region 方法
        /// <summary>自动扫描可用模块</summary>
        public void Scan()
        {
            foreach (var item in typeof(IEntityModule).GetAllSubclasses(true))
            {
                var module = item.CreateInstance() as IEntityModule;
                Add(module);
            }
        }

        /// <summary>添加实体模块</summary>
        /// <param name="module"></param>
        /// <returns></returns>
        public virtual Boolean Add(IEntityModule module)
        {
            if (!module.Init(EntityType)) return false;

            Modules.Add(module);

            return true;
        }

        /// <summary>添加实体模块</summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public virtual IEntityModule Add<T>() where T : IEntityModule, new()
        {
            var module = new T();
            if (Add(module)) return null;

            return module;
        }

        /// <summary>创建实体时执行模块</summary>
        /// <param name="entity"></param>
        /// <param name="forEdit"></param>
        public void Create(IEntity entity, Boolean forEdit)
        {
            foreach (var item in Modules)
            {
                item.Create(entity, forEdit);
            }
        }

        /// <summary>添加更新实体时验证</summary>
        /// <param name="entity"></param>
        /// <param name="isNew"></param>
        /// <returns></returns>
        public Boolean Valid(IEntity entity, Boolean isNew)
        {
            foreach (var item in Modules)
            {
                if (!item.Valid(entity, isNew)) return false;
            }

            return true;
        }
        #endregion

        #region ICollection<IEntityModule> 成员
        void ICollection<IEntityModule>.Add(IEntityModule item) { Add(item); }

        void ICollection<IEntityModule>.Clear() { Modules.Clear(); }

        Boolean ICollection<IEntityModule>.Contains(IEntityModule item) { return Modules.Contains(item); }

        void ICollection<IEntityModule>.CopyTo(IEntityModule[] array, Int32 arrayIndex) { Modules.CopyTo(array, arrayIndex); }

        Int32 ICollection<IEntityModule>.Count { get { return Modules.Count; } }

        Boolean ICollection<IEntityModule>.IsReadOnly { get { return (Modules as ICollection<IEntityModule>).IsReadOnly; } }

        Boolean ICollection<IEntityModule>.Remove(IEntityModule item) { return Modules.Remove(item); }
        #endregion

        #region IEnumerable<IEntityModule> 成员
        IEnumerator<IEntityModule> IEnumerable<IEntityModule>.GetEnumerator() { return Modules.GetEnumerator(); }
        #endregion

        #region IEnumerable 成员
        IEnumerator IEnumerable.GetEnumerator() { return Modules.GetEnumerator(); }
        #endregion
    }

    /// <summary>实体模块基类</summary>
    public abstract class EntityModule : IEntityModule
    {
        #region IEntityModule 成员
        /// <summary>为指定实体类初始化模块,返回是否支持</summary>
        /// <param name="entityType"></param>
        /// <returns></returns>
        public virtual Boolean Init(Type entityType) { return true; }

        /// <summary>创建实体对象</summary>
        /// <param name="entity"></param>
        /// <param name="forEdit"></param>
        public virtual void Create(IEntity entity, Boolean forEdit) { }

        /// <summary>验证实体对象</summary>
        /// <param name="entity"></param>
        /// <param name="isNew"></param>
        /// <returns></returns>
        public virtual Boolean Valid(IEntity entity, Boolean isNew) { return true; }
        #endregion

        #region 辅助
        /// <summary>设置脏数据项。如果某个键存在并且数据没有脏,则设置</summary>
        /// <param name="fieldNames"></param>
        /// <param name="entity"></param>
        /// <param name="name"></param>
        /// <param name="value"></param>
        /// <returns>返回是否成功设置了数据</returns>
        protected virtual Boolean SetNoDirtyItem(ICollection<String> fieldNames, IEntity entity, String name, Object value)
        {
            if (fieldNames.Contains(name) && !entity.Dirtys[name]) return entity.SetItem(name, value);

            return false;
        }

        private DictionaryCache<Type, ICollection<String>> _fieldNames = new DictionaryCache<Type, ICollection<String>>();
        /// <summary>获取实体类的字段名。带缓存</summary>
        /// <param name="entityType"></param>
        /// <returns></returns>
        protected ICollection<String> GetFieldNames(Type entityType)
        {
            return _fieldNames.GetItem(entityType, t =>
            {
                var fact = EntityFactory.CreateOperate(t);
                //return fact == null ? null : fact.FieldNames;
                if (fact == null) return null;

                return new HashSet<String>(fact.FieldNames);
            });
        }
        #endregion
    }
}