采用单对象缓存判断,减少一次查询
Stone authored at 2012-06-27 07:46:26
15.19 KiB
X
/*
 * XCoder v3.4.2011.0329
 * 作者:nnhy/X
 * 时间:2011-06-21 21:07:14
 * 版权:版权所有 (C) 新生命开发团队 2010
*/
using System;
using System.ComponentModel;
using System.Xml.Serialization;
using NewLife.Exceptions;
using NewLife.Log;
using XCode;

#if NET4
using System.Linq;
#else
using NewLife.Linq;
#endif

namespace NewLife.CommonEntity
{
    /// <summary>设置</summary>
    /// <remarks>所有设置项,都挂在单对象缓存上</remarks>
    [ModelCheckMode(ModelCheckModes.CheckTableWhenFirstUse)]
    public class Setting : Setting<Setting> { }

    /// <summary>设置</summary>
    /// <remarks>所有设置项,都挂在单对象缓存上</remarks>
    public partial class Setting<TEntity> : Entity<TEntity> where TEntity : Setting<TEntity>, new()
    {
        #region 对象操作
        static Setting()
        {
            // 用于引发基类的静态构造函数,所有层次的泛型实体类都应该有一个
            TEntity entity = new TEntity();

            //var cache = Meta.SingleCache;
            ////cache.AllowNull = false;
            ////cache.AutoSave = true;
            //cache.FindKeyMethod = k =>
            //{
            //    var key = k.ToString();
            //    var p = key.IndexOf("_");
            //    return FindByParentIDAndName(Int32.Parse(key.Substring(0, p)), key.Substring(p + 1));
            //};
        }

        /// <summary>验证数据,通过抛出异常的方式提示验证失败。</summary>
        /// <param name="isNew"></param>
        public override void Valid(bool isNew)
        {
            if (String.IsNullOrEmpty(Name)) throw new ArgumentNullException(_.Name, _.Name.DisplayName + "不能为空!");

            base.Valid(isNew);
        }

        /// <summary>根据指定键检查数据,返回数据是否已存在</summary>
        /// <param name="names"></param>
        /// <returns></returns>
        public override bool Exist(params string[] names)
        {
            // 采用单对象缓存判断,减少一次查询
            if (names.Length == 2 && names[0] == _.ParentID && names[1] == _.Name)
            {
                var p = FindByID(ParentID);
                return p.Childs.Exists(_.Name, Name);
            }

            return base.Exist(names);
        }

        /// <summary>添加后清理上级的子级缓存</summary>
        /// <returns></returns>
        public override int Insert()
        {
            // 清理缓存
            var ps = new TEntity[] { Parent, null };

            var rs = base.Insert();
            // 加入到单对象缓存
            Meta.SingleCache.Add(this.ID, this as TEntity);

            // 清理缓存
            ps[1] = Parent;
            foreach (var p in ps)
            {
                if (p != null)
                {
                    // 可以试试不清理,查找缓存后加入,必须查找缓存
                    var list = p._Childs;
                    if (list != null && !list.Exists(_.ID, this.ID)) list.Add(FindByID(this.ID));
                }
            }

            return rs;
        }

        /// <summary>已重载。</summary>
        /// <returns></returns>
        protected override int OnDelete()
        {
            var list = Childs;
            //if (list != null) list.Delete();
            if (list == null || list.Count > 0) throw new XException("设置项{0}下有{1}个子项,禁止删除!", Name, list == null ? 0 : list.Count);

            return base.OnDelete();
        }
        #endregion

        #region 扩展属性
        /// <summary>类型编码</summary>
        public TypeCode KindCode { get { return (TypeCode)Kind; } set { Kind = (Int32)value; } }

        private static Object _lock_Root = new Object();
        private static TEntity _Root;
        /// <summary>根</summary>
        public static TEntity Root
        {
            get
            {
                if (_Root != null) return _Root;
                lock (_lock_Root)
                {
                    if (_Root != null) return _Root;

                    _Root = new TEntity();
                    //Meta.OnDataChange += delegate { _Root = null; };
                }
                return _Root;
            }
            set { _Root = null; }
        }

        /// <summary>父节点</summary>
        [XmlIgnore]
        public TEntity Parent { get { return FindByID(ParentID); } }

        /// <summary>父级</summary>
        public String ParentName { get { return Parent != null ? Parent.Name : null; } }

        [NonSerialized]
        private EntityList<TEntity> _Childs;
        /// <summary>子节点</summary>
        public EntityList<TEntity> Childs
        {
            get
            {
                if (_Childs == null && !Dirtys["Childs"])
                {
                    // 先从数据库读取,然后从实体缓存读取
                    var list = FindAll(_.ParentID, ID);

                    _Childs = new EntityList<TEntity>(list.ToList().Select(e => FindByID(e.ID)));

                    Dirtys["Childs"] = true;
                }
                return _Childs;
            }
            set { _Childs = value; }
        }
        #endregion

        #region 扩展查询
        ///// <summary>根据父编号、名称查找</summary>
        ///// <param name="parentid">父编号</param>
        ///// <param name="name">名称</param>
        ///// <returns></returns>
        //[DataObjectMethod(DataObjectMethodType.Select, false)]
        //static TEntity FindByParentIDAndName(Int32 parentid, String name)
        //{
        //    //if (Meta.Count >= 1000)
        //    return Find(new String[] { _.ParentID, _.Name }, new Object[] { parentid, name });
        //    //else // 实体缓存
        //    //    return Meta.Cache.Entities.Find(e => e.ParentID == parentid && e.Name == name);
        //}

        ///// <summary>根据父编号、名称查找,单对象缓存</summary>
        ///// <param name="parentid">父编号</param>
        ///// <param name="name">名称</param>
        ///// <returns></returns>
        //public static TEntity FindWithCache(Int32 parentid, String name)
        //{
        //    var key = String.Format("{0}_{1}", parentid, name);
        //    return Meta.SingleCache[key];
        //}

        /// <summary>根据名称查找子节点</summary>
        /// <param name="name">名称</param>
        /// <returns></returns>
        public TEntity FindByName(String name)
        {
            if (String.IsNullOrEmpty(name)) return null;

            var list = Childs;
            //XTrace.WriteLine("FindByName:{0}.Childs[{1}]", Name, _Childs.Count);
            if (list == null || list.Count < 1) return null;

            return list.Find(_.Name, name);
        }

        /// <summary>根据编号查找</summary>
        /// <param name="id">编号</param>
        /// <returns></returns>
        [DataObjectMethod(DataObjectMethodType.Select, false)]
        public static TEntity FindByID(Int32 id)
        {
            if (id <= 0) return Root;

            //if (Meta.Count >= 1000)
            //    return Find(_.ID, id);
            //else // 实体缓存
            //    return Meta.Cache.Entities.Find(_.ID, id);
            // 单对象缓存
            return Meta.SingleCache[id];
        }
        #endregion

        #region 对象操作
        ///// <summary>
        ///// 已重载。基类先调用Valid(true)验证数据,然后在事务保护内调用OnInsert
        ///// </summary>
        ///// <returns></returns>
        //public override Int32 Insert()
        //{
        //    return base.Insert();
        //}

        ///// <summary>
        ///// 已重载。在事务保护范围内处理业务,位于Valid之后
        ///// </summary>
        ///// <returns></returns>
        //protected override Int32 OnInsert()
        //{
        //    return base.OnInsert();
        //}

        ///// <summary>
        ///// 验证数据,通过抛出异常的方式提示验证失败。
        ///// </summary>
        ///// <param name="isNew"></param>
        //public override void Valid(Boolean isNew)
        //{
        //    // 建议先调用基类方法,基类方法会对唯一索引的数据进行验证
        //    base.Valid(isNew);

        //    // 这里验证参数范围,建议抛出参数异常,指定参数名,前端用户界面可以捕获参数异常并聚焦到对应的参数输入框
        //    if (String.IsNullOrEmpty(_.Name)) throw new ArgumentNullException(_.Name, _.Name.Description + "无效!");
        //    if (!isNew && ID < 1) throw new ArgumentOutOfRangeException(_.ID, _.ID.Description + "必须大于0!");

        //    // 在新插入数据或者修改了指定字段时进行唯一性验证,CheckExist内部抛出参数异常
        //    if (isNew || Dirtys[_.Name]) CheckExist(_.Name);
        //    if (isNew || Dirtys[_.Name] || Dirtys[_.DbType]) CheckExist(_.Name, _.DbType);
        //    if ((isNew || Dirtys[_.Name]) && Exist(_.Name)) throw new ArgumentException(_.Name, "值为" + Name + "的" + _.Name.Description + "已存在!");
        //}


        ///// <summary>
        ///// 首次连接数据库时初始化数据,仅用于实体类重载,用户不应该调用该方法
        ///// </summary>
        //[EditorBrowsable(EditorBrowsableState.Never)]
        //protected override void InitData()
        //{
        //    base.InitData();

        //    // InitData一般用于当数据表没有数据时添加一些默认数据,该实体类的任何第一次数据库操作都会触发该方法,默认异步调用
        //    // Meta.Count是快速取得表记录数
        //    if (Meta.Count > 0) return;

        //    // 需要注意的是,如果该方法调用了其它实体类的首次数据库操作,目标实体类的数据初始化将会在同一个线程完成
        //    if (XTrace.Debug) XTrace.WriteLine("开始初始化{0}管理员数据……", typeof(TEntity).Name);

        //    TEntity user = new TEntity();
        //    user.Name = "admin";
        //    user.Password = DataHelper.Hash("admin");
        //    user.DisplayName = "管理员";
        //    user.RoleID = 1;
        //    user.IsEnable = true;
        //    user.Insert();

        //    if (XTrace.Debug) XTrace.WriteLine("完成初始化{0}管理员数据!", typeof(TEntity).Name);
        //}
        #endregion

        #region 高级查询
        #endregion

        #region 扩展操作
        #endregion

        #region 业务
        /// <summary>若不存在则创建指定名称的子级</summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public virtual ISetting Create(String name)
        {
            if (String.IsNullOrEmpty(name)) throw new ArgumentNullException("name");

            var entity = FindByName(name);
            if (entity == null)
            {
                entity = new TEntity();
                entity.ParentID = ID;
                entity.Name = name;
                entity.Save();

                // 如果空,需要重新查找,让其进入缓存
                entity = FindByID(entity.ID);
                //entity = FindByName(name);
                if (entity == null) throw new XException("设计错误!新添加的设置项{0}马上进行单对象缓存查找居然为空!", name);
            }

            return entity;
        }

        //ISetting ISetting.Create(String name) { return Create(name); }

        /// <summary>取值</summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public virtual T Get<T>() { return (T)Convert.ChangeType(Value, Type.GetTypeCode(typeof(T))); }

        /// <summary>取值</summary>
        /// <returns></returns>
        public virtual Object Get()
        {
            if (KindCode == TypeCode.Empty) return null;

            return Convert.ChangeType(Value, KindCode);
        }

        /// <summary>设置值</summary>
        /// <param name="val"></param>
        public virtual void Set<T>(T val)
        {
            Value = val != null ? "" + val : null;
            KindCode = Type.GetTypeCode(typeof(T));
            Save();
        }

        /// <summary>设置值</summary>
        /// <param name="val"></param>
        public virtual void Set(Object val)
        {
            if (val == null)
            {
                KindCode = TypeCode.Empty;
                Value = null;
            }
            else
            {
                KindCode = Type.GetTypeCode(val.GetType());
                Value = "" + val;
            }
            Save();
        }

        /// <summary>确保设置项存在</summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <param name="defval"></param>
        /// <param name="displayName"></param>
        /// <returns></returns>
        public virtual ISetting Ensure<T>(String name, T defval, String displayName)
        {
            if (String.IsNullOrEmpty(name)) throw new ArgumentNullException("name");

            // 是否空
            var isnull = false;

            var entity = FindByName(name);
            if (entity == null)
            {
                entity = new TEntity();
                entity.ParentID = ID;
                entity.Name = name;

                isnull = true;
            }
            // Set放在最后,因为里面有个Save,避免做了一次Insert后再做一次Update
            if (String.IsNullOrEmpty(entity.DisplayName)) entity.DisplayName = displayName;
            if (String.IsNullOrEmpty(entity.Value)) entity.Set<T>(defval);
            entity.Save();

            // 如果空,需要重新查找,让其进入缓存
            if (isnull) entity = FindByName(name);

            return this;
        }
        #endregion
    }

    partial interface ISetting
    {
        /// <summary>若不存在则创建指定名称的子级</summary>
        /// <param name="name"></param>
        /// <returns></returns>
        ISetting Create(String name);

        /// <summary>取值</summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        T Get<T>();

        ///// <summary>取值</summary>
        ///// <returns></returns>
        //Object Get();

        /// <summary>设置值</summary>
        /// <param name="val"></param>
        void Set<T>(T val);

        ///// <summary>设置值</summary>
        ///// <param name="val"></param>
        //void Set(Object val);

        /// <summary>确保设置项存在</summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <param name="defval"></param>
        /// <param name="displayName"></param>
        /// <returns></returns>
        ISetting Ensure<T>(String name, T defval, String displayName);

        /// <summary>保存</summary>
        /// <returns></returns>
        Int32 Save();
    }
}