必须填写至少10个字的日志
nnhy authored at 2012-07-27 18:48:21
60.42 KiB
X
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.IO;
using System.Text;
using System.Xml.Serialization;
using NewLife.Collections;
using NewLife.IO;
using NewLife.Reflection;
using XCode.Common;
using XCode.Configuration;
using XCode.DataAccessLayer;
using XCode.Exceptions;
using XCode.Model;

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

namespace XCode
{
    /// <summary>Êý¾ÝʵÌåÀà»ùÀà¡£ËùÓÐÊý¾ÝʵÌåÀ඼±ØÐë¼Ì³Ð¸ÃÀà¡£</summary>
    [Serializable]
    public partial class Entity<TEntity> : EntityBase where TEntity : Entity<TEntity>, new()
    {
        #region ¹¹Ô캯Êý
        /// <summary>¾²Ì¬¹¹Ôì</summary>
        static Entity()
        {
            DAL.WriteDebugLog("¿ªÊ¼³õʼ»¯ÊµÌåÀà{0}", Meta.ThisType.Name);

            EntityFactory.Register(Meta.ThisType, new EntityOperate());

            // 1£¬¿ÉÒÔ³õʼ»¯¸ÃʵÌåÀàÐ͵IJÙ×÷¹¤³§
            // 2£¬CreateOperate½«»áʵÀý»¯Ò»¸öTEntity¶ÔÏ󣬴ӶøÒý·¢TEntityµÄ¾²Ì¬¹¹Ô캯Êý£¬
            // ±ÜÃâʵ¼ÊÓ¦ÓÃÖУ¬Ö±½Óµ÷ÓÃEntityµÄ¾²Ì¬·½·¨Ê±£¬Ã»ÓÐÒý·¢TEntityµÄ¾²Ì¬¹¹Ô캯Êý¡£
            TEntity entity = new TEntity();

            ////! ´óʯͷ 2011-03-14 ÒÔϹý³Ì¸ÄΪÒì²½´¦Àí
            ////  ÒÑÈ·ÈÏ£¬µ±ÊµÌåÀྲ̬¹¹Ô캯ÊýÖÐʹÓÃÁËEntityFactory.CreateOperate(Type)·½·¨Ê±£¬¿ÉÄܳöÏÖËÀËø¡£
            ////  ÒòΪÁ½Õ߶¼»áÕù¶áEntityFactoryÖеÄop_cache£¬¶øCreateOperate(Type)Äõ½op_cacheºó£¬»¹ÐèÒªµÈ´ýµ±Ç°¾²Ì¬¹¹Ô캯ÊýÖ´ÐÐÍê³É¡£
            ////  ²»È·¶¨ÕâÑù×ÓÊÇ·ñ´øÀ´ºóÒÅÖ¢
            //ThreadPool.QueueUserWorkItem(delegate
            //{
            //    EntityFactory.CreateOperate(Meta.ThisType, entity);
            //});

            DAL.WriteDebugLog("Íê³É³õʼ»¯ÊµÌåÀà{0}", Meta.ThisType.Name);
        }

        /// <summary>
        /// ´´½¨ÊµÌå¡£¿ÉÒÔÖØд¸Ä·½·¨ÒÔʵÏÖʵÌå¶ÔÏóµÄһЩ³õʼ»¯¹¤×÷¡£
        /// Çмǣ¬Ð´ÎªÊµÀý·½·¨½ö½öÊÇΪÁË·½±ãÖØÔØ£¬ËùÒª·µ»ØµÄʵÀý¾ø¶Ô²»»áÊǵ±Ç°ÊµÀý¡£
        /// </summary>
        /// <param name="forEdit">ÊÇ·ñΪÁ˱༭¶ø´´½¨£¬Èç¹ûÊÇ£¬¿ÉÒÔÔÙ´Î×öһЩÏà¹ØµÄ³õʼ»¯¹¤×÷</param>
        /// <returns></returns>
        protected virtual TEntity CreateInstance(Boolean forEdit = false)
        {
            //return new TEntity();
            // new TEntity»á±»±àÒëΪActivator.CreateInstance<TEntity>()£¬»¹²»ÈçActivator.CreateInstance()ÄØ
            // Activator.CreateInstance()Óлº´æ¹¦ÄÜ£¬¶ø·ºÐ͵ÄÄǸöûÓÐ
            //return Activator.CreateInstance(Meta.ThisType) as TEntity;
            return TypeX.CreateInstance(Meta.ThisType) as TEntity;
        }
        #endregion

        #region Ìî³äÊý¾Ý
        /// <summary>¼ÓÔؼǼ¼¯¡£ÎÞÊý¾Ýʱ·µ»Ø¿Õ¼¯ºÏ¶ø²»ÊÇnull¡£</summary>
        /// <param name="ds">¼Ç¼¼¯</param>
        /// <returns>ʵÌåÊý×é</returns>
        public static EntityList<TEntity> LoadData(DataSet ds) { return LoadData(ds.Tables[0]); }

        /// <summary>¼ÓÔØÊý¾Ý±í¡£ÎÞÊý¾Ýʱ·µ»Ø¿Õ¼¯ºÏ¶ø²»ÊÇnull¡£</summary>
        /// <param name="dt">Êý¾Ý±í</param>
        /// <returns>ʵÌåÊý×é</returns>
        public static EntityList<TEntity> LoadData(DataTable dt)
        {
            var list = dreAccessor.LoadData(dt);
            // ÉèÖÃĬÈÏÀÛ¼Ó×Ö¶Î
            var fs = AdditionalFields;
            if (fs.Count > 0)
            {
                foreach (var entity in list)
                {
                    foreach (var item in fs)
                    {
                        entity.SetAdditionalField(item);
                    }
                }
            }
            foreach (EntityBase entity in list)
            {
                entity._IsFromDatabase = true;
            }
            if (list is EntityList<TEntity>) return list as EntityList<TEntity>;

            return new EntityList<TEntity>(list);
        }

        /// <summary>´ÓÒ»¸öÊý¾ÝÐжÔÏó¼ÓÔØÊý¾Ý¡£²»¼ÓÔعØÁª¶ÔÏó¡£</summary>
        /// <param name="dr">Êý¾ÝÐÐ</param>
        public override void LoadData(DataRow dr)
        {
            if (dr != null)
            {
                dreAccessor.LoadData(dr, this);
                _IsFromDatabase = true;
            }
        }

        /// <summary>¼ÓÔØÊý¾Ý¶ÁдÆ÷¡£ÎÞÊý¾Ýʱ·µ»Ø¿Õ¼¯ºÏ¶ø²»ÊÇnull¡£</summary>
        /// <param name="dr">Êý¾Ý¶ÁдÆ÷</param>
        /// <returns>ʵÌåÊý×é</returns>
        public static EntityList<TEntity> LoadData(IDataReader dr)
        {
            var list = dreAccessor.LoadData(dr);

            // ÉèÖÃĬÈÏÀÛ¼Ó×Ö¶Î
            var fs = AdditionalFields;
            if (fs.Count > 0)
            {
                foreach (var entity in list)
                {
                    foreach (var item in fs)
                    {
                        entity.SetAdditionalField(item);
                    }
                }
            }
            foreach (EntityBase entity in list)
            {
                entity._IsFromDatabase = true;
            }
            if (list is EntityList<TEntity>) return list as EntityList<TEntity>;

            return new EntityList<TEntity>(list);
        }

        /// <summary>´ÓÒ»¸öÊý¾ÝÐжÔÏó¼ÓÔØÊý¾Ý¡£²»¼ÓÔعØÁª¶ÔÏó¡£</summary>
        /// <param name="dr">Êý¾Ý¶ÁдÆ÷</param>
        public override void LoadDataReader(IDataReader dr)
        {
            if (dr != null)
            {
                dreAccessor.LoadData(dr, this);
                _IsFromDatabase = true;

                // ÉèÖÃĬÈÏÀÛ¼Ó×Ö¶Î
                var fs = AdditionalFields;
                if (fs.Count > 0)
                {
                    foreach (var item in fs)
                    {
                        SetAdditionalField(item);
                    }
                }
            }
        }

        /// <summary>°ÑÊý¾Ý¸´ÖƵ½Êý¾ÝÐжÔÏóÖС£</summary>
        /// <param name="dr">Êý¾ÝÐÐ</param>
        public virtual DataRow ToData(ref DataRow dr) { return dr == null ? null : dreAccessor.ToData(this, ref dr); }

        private static IDataRowEntityAccessor dreAccessor { get { return XCodeService.CreateDataRowEntityAccessor(Meta.ThisType); } }
        #endregion

        #region ²Ù×÷
        private static IEntityPersistence persistence { get { return XCodeService.Container.ResolveInstance<IEntityPersistence>(); } }

        /// <summary>²åÈëÊý¾Ý£¬Í¨¹ýµ÷ÓÃOnInsertʵÏÖ£¬ÁíÍâÔö¼ÓÁËÊý¾ÝÑéÖ¤ºÍÊÂÎñ±£»¤Ö§³Ö£¬½«À´¿ÉÄÜʵÏÖʼþÖ§³Ö¡£</summary>
        /// <returns></returns>
        public override Int32 Insert() { return DoAction(OnInsert, true); }

        /// <summary>°Ñ¸Ã¶ÔÏó³Ö¾Ã»¯µ½Êý¾Ý¿â¡£¸Ã·½·¨ÌṩԭÉúµÄÊý¾Ý²Ù×÷£¬²»½¨ÒéÖØÔØ£¬½¨ÒéÖØÔØInsert´úÌæ¡£</summary>
        /// <returns></returns>
        protected virtual Int32 OnInsert()
        {
            var rs = persistence.Insert(this);

            // Èç¹ûµ±Ç°ÔÚÊÂÎñÖУ¬²¢Ê¹ÓÃÁË»º´æ£¬Ôò³¢ÊÔ¸üлº´æ
            if (Meta.UsingTrans && Meta.Cache.Using)
            {
                // ¾¡¹ÜÓÃÁËÊÂÎñ±£»¤£¬µ«ÊÇÈÔÈ»¿ÉÄÜÓбðµÄµØ·½µ¼ÖÂʵÌ建´æ¸üУ¬ÕâµãÎñ±ØҪעÒâ
                var fi = Meta.Unique;
                var entity = Meta.Cache.Entities.Find(fi.Name, this[fi.Name]);
                if (entity != null)
                {
                    if (entity != this) entity.CopyFrom(this);
                }
                else
                    Meta.Cache.Entities.Add(this as TEntity);
            }

            return rs;
        }

        /// <summary>¸üÐÂÊý¾Ý£¬Í¨¹ýµ÷ÓÃOnUpdateʵÏÖ£¬ÁíÍâÔö¼ÓÁËÊý¾ÝÑéÖ¤ºÍÊÂÎñ±£»¤Ö§³Ö£¬½«À´¿ÉÄÜʵÏÖʼþÖ§³Ö¡£</summary>
        /// <returns></returns>
        public override Int32 Update() { return DoAction(OnUpdate, false); }

        /// <summary>¸üÐÂÊý¾Ý¿â</summary>
        /// <returns></returns>
        protected virtual Int32 OnUpdate()
        {
            var rs = persistence.Update(this);

            // Èç¹ûµ±Ç°ÔÚÊÂÎñÖУ¬²¢Ê¹ÓÃÁË»º´æ£¬Ôò³¢ÊÔ¸üлº´æ
            if (Meta.UsingTrans && Meta.Cache.Using)
            {
                // ¾¡¹ÜÓÃÁËÊÂÎñ±£»¤£¬µ«ÊÇÈÔÈ»¿ÉÄÜÓбðµÄµØ·½µ¼ÖÂʵÌ建´æ¸üУ¬ÕâµãÎñ±ØҪעÒâ
                var fi = Meta.Unique;
                var entity = Meta.Cache.Entities.Find(fi.Name, this[fi.Name]);
                if (entity != null)
                {
                    if (entity != this) entity.CopyFrom(this);
                }
                else
                    Meta.Cache.Entities.Add(this as TEntity);
            }

            return rs;
        }

        /// <summary>ɾ³ýÊý¾Ý£¬Í¨¹ýµ÷ÓÃOnDeleteʵÏÖ£¬ÁíÍâÔö¼ÓÁËÊý¾ÝÑéÖ¤ºÍÊÂÎñ±£»¤Ö§³Ö£¬½«À´¿ÉÄÜʵÏÖʼþÖ§³Ö¡£</summary>
        /// <remarks>
        /// ɾ³ýʱ£¬Èç¹ûÓÐÇÒ½öÓÐÖ÷¼üÓÐÔàÊý¾Ý£¬Ôò¿ÉÄÜÊÇObjectDataSourceÖ®ÀàµÄɾ³ý²Ù×÷¡£
        /// ¸ÃÇé¿öÏ£¬ÊµÌåÀàûÓÐÍêÕûµÄÐÅÏ¢£¨½öÓÐÖ÷¼üÐÅÏ¢£©£¬½«»áµ¼ÖÂÎÞ·¨Í¨¹ýÀ©Õ¹ÊôÐÔɾ³ý¸½ÊôÊý¾Ý¡£
        /// Èç¹ûÐèÒª±Ü¿ª¸Ã»úÖÆ£¬ÇëÇå¿ÕÔàÊý¾Ý¡£
        /// </remarks>
        /// <returns></returns>
        public override Int32 Delete()
        {
            if (Dirtys.Count > 0)
            {
                // ÊÇ·ñÓÐÇÒ½öÓÐÖ÷¼üÓÐÔàÊý¾Ý
                var names = Meta.Table.PrimaryKeys.Select(f => f.Name).OrderBy(k => k).ToArray();
                // ÔàÊý¾ÝÀïÃæÊÇ·ñ´æÔÚ·ÇÖ÷¼üÇÒΪtrueµÄ
                var names2 = Dirtys.Where(d => d.Value).Select(d => d.Key).OrderBy(k => k).ToArray();
                // ÐòÁÐÏàµÈ£¬·ûºÏÌõ¼þ
                if (names.SequenceEqual(names2))
                {
                    // Ôٴβéѯ
                    TEntity entity = Find(persistence.GetPrimaryCondition(this));
                    // Èç¹ûÄ¿±êÊý¾Ý²»´æÔÚ£¬¾Íû±ØҪɾ³ýÁË
                    if (entity == null) return 0;

                    // ¸´ÖÆÔàÊý¾ÝºÍÀ©Õ¹Êý¾Ý
                    //names.ForEach((n, i) => entity.Dirtys[n] = true);
                    //this.Extends.ForEach((d, i) => entity.Extends[d.Key] = d.Value);
                    foreach (var item in names)
                    {
                        entity.Dirtys[item] = true;
                    }
                    foreach (var item in Extends)
                    {
                        entity.Extends[item.Key] = item.Value;
                    }

                    return entity.OnDelete();
                }
            }

            return DoAction(OnDelete, null);
        }

        /// <summary>´ÓÊý¾Ý¿âÖÐɾ³ý¸Ã¶ÔÏó</summary>
        /// <returns></returns>
        protected virtual Int32 OnDelete()
        {
            var rs = persistence.Delete(this);

            // Èç¹ûµ±Ç°ÔÚÊÂÎñÖУ¬²¢Ê¹ÓÃÁË»º´æ£¬Ôò³¢ÊÔ¸üлº´æ
            if (Meta.UsingTrans && Meta.Cache.Using)
            {
                var fi = Meta.Unique;
                //var entity = Meta.Cache.Entities.Find(fi.Name, this[fi.Name]);
                //if (entity != null) Meta.Cache.Entities.Remove(entity);

                if (fi != null)
                    Meta.Cache.Entities.RemoveAll(e => Object.Equals(e[fi.Name], this[fi.Name]));
            }

            return rs;
        }

        Int32 DoAction(Func<Int32> func, Boolean? isnew)
        {
            if (isnew != null && enableValid) Valid(isnew.Value);

            Meta.BeginTrans();
            try
            {
                Int32 rs = func();

                Meta.Commit();

                return rs;
            }
            catch { Meta.Rollback(); throw; }
        }

        /// <summary>±£´æ¡£¸ù¾ÝÖ÷¼ü¼ì²éÊý¾Ý¿âÖÐÊÇ·ñÒÑ´æÔڸöÔÏó£¬ÔÙ¾ö¶¨µ÷ÓÃInsert»òUpdate</summary>
        /// <returns></returns>
        public override Int32 Save()
        {
            //ÓÅÏÈʹÓÃ×ÔÔö×Ö¶ÎÅжÏ
            FieldItem fi = Meta.Table.Identity;
            if (fi != null) return Convert.ToInt64(this[fi.Name]) > 0 ? Update() : Insert();

            fi = Meta.Unique;
            //if (fi != null) return Helper.IsNullKey(this[fi.Name]) ? Insert() : Update();
            // Èç¹ûΨһÖ÷¼ü²»Îª¿Õ£¬Ó¦¸Ãͨ¹ýºóÃæÅжϣ¬¶ø²»ÊÇÖ±½ÓUpdate
            if (fi != null && Helper.IsNullKey(this[fi.Name])) return Insert();

            return FindCount(persistence.GetPrimaryCondition(this), null, null, 0, 0) > 0 ? Update() : Insert();
        }

        /// <summary>²»ÐèÒªÑéÖ¤µÄ±£´æ£¬²»Ö´ÐÐValid£¬Ò»°ãÓÃÓÚ¿ìËÙµ¼ÈëÊý¾Ý</summary>
        /// <returns></returns>
        public override Int32 SaveWithoutValid()
        {
            enableValid = false;
            try { return Save(); }
            finally { enableValid = true; }
        }

        [NonSerialized]
        Boolean enableValid = true;

        /// <summary>ÑéÖ¤Êý¾Ý£¬Í¨¹ýÅ׳öÒì³£µÄ·½Ê½ÌáʾÑé֤ʧ°Ü¡£½¨ÒéÖØдÕßµ÷ÓûùÀàµÄʵÏÖ£¬ÒòΪ½«À´¿ÉÄܸù¾ÝÊý¾Ý×ֶεÄÌØÐÔ½øÐÐÊý¾ÝÑéÖ¤¡£</summary>
        /// <param name="isNew">ÊÇ·ñÐÂÊý¾Ý</param>
        public virtual void Valid(Boolean isNew)
        {
            // ¸ù¾ÝË÷Òý£¬ÅжÏΨһÐÔ
            IDataTable table = Meta.Table.DataTable;
            if (table.Indexes != null && table.Indexes.Count > 0)
            {
                // ±éÀúËùÓÐË÷Òý
                foreach (IDataIndex item in table.Indexes)
                {
                    // Ö»´¦ÀíΨһË÷Òý
                    if (!item.Unique) continue;

                    // ÐèҪתΪ±ðÃû£¬Ò²¾ÍÊÇ×Ö¶ÎÃû
                    IDataColumn[] columns = table.GetColumns(item.Columns);
                    if (columns == null || columns.Length < 1) continue;

                    // ²»´¦Àí×ÔÔö
                    if (columns.All(c => c.Identity)) continue;

                    // ¼Ç¼×Ö¶ÎÊÇ·ñÓиüÐÂ
                    Boolean changed = false;
                    if (!isNew) changed = columns.Any(c => Dirtys[c.Alias]);

                    // ´æÔÚ¼ì²é
                    if (isNew || changed) CheckExist(columns.Select(c => c.Alias).Distinct().ToArray());
                }
            }
        }

        /// <summary>¸ù¾ÝÖ¸¶¨¼ü¼ì²éÊý¾ÝÊÇ·ñÒÑ´æÔÚ£¬Èô²»´æÔÚ£¬Å׳öArgumentOutOfRangeExceptionÒì³£</summary>
        /// <param name="names"></param>
        public virtual void CheckExist(params String[] names)
        {
            if (Exist(names))
            {
                StringBuilder sb = new StringBuilder();
                String name = null;
                for (int i = 0; i < names.Length; i++)
                {
                    if (sb.Length > 0) sb.Append("£¬");

                    FieldItem field = Meta.Table.FindByName(names[i]);
                    if (field != null) name = field.Description;
                    if (String.IsNullOrEmpty(name)) name = names[i];

                    sb.AppendFormat("{0}={1}", name, this[names[i]]);
                }

                name = Meta.Table.Description;
                if (String.IsNullOrEmpty(name)) name = Meta.ThisType.Name;
                sb.AppendFormat(" µÄ{0}ÒÑ´æÔÚ£¡", name);

                throw new ArgumentOutOfRangeException(String.Join(",", names), this[names[0]], sb.ToString());
            }
        }

        /// <summary>¸ù¾ÝÖ¸¶¨¼ü¼ì²éÊý¾Ý£¬·µ»ØÊý¾ÝÊÇ·ñÒÑ´æÔÚ</summary>
        /// <param name="names"></param>
        /// <returns></returns>
        public virtual Boolean Exist(params String[] names)
        {
            // ¸ù¾ÝÖ¸¶¨¼ü²éÕÒËùÓзûºÏµÄÊý¾Ý£¬È»ºó±È¶Ô¡£
            // µ±È»£¬Ò²¿ÉÒÔͨ¹ýÖ¸¶¨¼üºÍÖ÷¼üÅäºÏ£¬ÕÒµ½ÓµÓÐÖ¸¶¨¼ü£¬µ«ÊDz»Êǵ±Ç°Ö÷¼üµÄÊý¾Ý£¬Ö»²é¼Ç¼Êý¡£
            Object[] values = new Object[names.Length];
            for (int i = 0; i < names.Length; i++)
            {
                values[i] = this[names[i]];
            }

            var field = Meta.Unique;
            if (!Meta.Cache.Using)
            {
                // Èç¹ûÊÇ¿ÕÖ÷¼ü£¬Ôò²ÉÓÃÖ±½ÓÅжϼǼÊýµÄ·½Ê½£¬ÒÔ¼Ó¿ìËÙ¶È
                if (Helper.IsNullKey(this[field.Name])) return FindCount(names, values) > 0;

                var list = FindAll(names, values);
                if (list == null || list.Count < 1) return false;
                if (list.Count > 1) return true;

                return !Object.Equals(this[field.Name], list[0][field.Name]);
            }
            else
            {
                // Èç¹ûÊÇ¿ÕÖ÷¼ü£¬Ôò²ÉÓÃÖ±½ÓÅжϼǼÊýµÄ·½Ê½£¬ÒÔ¼Ó¿ìËÙ¶È
                if (Helper.IsNullKey(this[field.Name])) return Meta.Cache.Entities.FindAll(names, values).Count > 0;

                var list = Meta.Cache.Entities.FindAll(names, values);
                if (list == null || list.Count < 1) return false;
                if (list.Count > 1) return true;

                return !Object.Equals(this[field.Name], list[0][field.Name]);
            }
        }
        #endregion

        #region ²éÕÒµ¥¸öʵÌå
        /// <summary>¸ù¾ÝÊôÐÔÒÔ¼°¶ÔÓ¦µÄÖµ£¬²éÕÒµ¥¸öʵÌå</summary>
        /// <param name="name">ÊôÐÔÃû³Æ</param>
        /// <param name="value">ÊôÐÔÖµ</param>
        /// <returns></returns>
        [DataObjectMethod(DataObjectMethodType.Select, false)]
        public static TEntity Find(String name, Object value) { return Find(new String[] { name }, new Object[] { value }); }

        /// <summary>¸ù¾ÝÊôÐÔÁбíÒÔ¼°¶ÔÓ¦µÄÖµÁÐ±í£¬²éÕÒµ¥¸öʵÌå</summary>
        /// <param name="names">ÊôÐÔÃû³Æ¼¯ºÏ</param>
        /// <param name="values">ÊôÐÔÖµ¼¯ºÏ</param>
        /// <returns></returns>
        public static TEntity Find(String[] names, Object[] values)
        {
            // ÅжÏ×ÔÔöºÍÖ÷¼ü
            if (names != null && names.Length == 1)
            {
                FieldItem field = Meta.Table.FindByName(names[0]);
                if (field != null && (field.IsIdentity || field.PrimaryKey))
                {
                    // Ψһ¼üΪ×ÔÔöÇÒ²ÎÊýСÓÚµÈÓÚ0ʱ£¬·µ»Ø¿Õ
                    if (Helper.IsNullKey(values[0])) return null;

                    return FindUnique(MakeCondition(field, values[0], "="));
                }
            }

            // ÅжÏΨһË÷Òý£¬Î¨Ò»Ë÷ÒýÒ²²»ÐèÒª·ÖÒ³
            IDataIndex di = Meta.Table.DataTable.GetIndex(names);
            if (di != null && di.Unique) return FindUnique(MakeCondition(names, values, "And"));

            return Find(MakeCondition(names, values, "And"));
        }

        /// <summary>
        /// ¸ù¾ÝÌõ¼þ²éÕÒΨһµÄµ¥¸öʵÌ壬ÒòΪÊÇΨһµÄ£¬ËùÒÔ²»ÐèÒª·ÖÒ³ºÍÅÅÐò¡£
        /// Èç¹û²»È·¶¨ÊÇ·ñΨһ£¬Ò»¶¨²»Òªµ÷Óø÷½·¨£¬·ñÔò»á·µ»Ø´óÁ¿µÄÊý¾Ý¡£
        /// </summary>
        /// <param name="whereClause">²éѯÌõ¼þ</param>
        /// <returns></returns>
        static TEntity FindUnique(String whereClause)
        {
            SelectBuilder builder = new SelectBuilder();
            builder.Table = Meta.FormatName(Meta.TableName);
            // ½÷¼Ç£ºÄ³Ð©ÏîÄ¿ÖпÉÄÜÔÚwhereÖÐʹÓÃÁËGroupBy£¬ÔÚ·Öҳʱ¿ÉÄܱ¨´í
            builder.Where = whereClause;
            IList<TEntity> list = LoadData(Meta.Query(builder, 0, 0));
            if (list == null || list.Count < 1) return null;

            if (list.Count > 1 && DAL.Debug)
            {
                DAL.WriteDebugLog("µ÷ÓÃFindUnique(\"{0}\")²»ºÏÀí£¬Ö»Óзµ»ØΨһ¼Ç¼µÄ²éѯÌõ¼þ²ÅÔÊÐíµ÷Óã¡", whereClause);
                NewLife.Log.XTrace.DebugStack(5);
            }
            return list[0];
        }

        /// <summary>¸ù¾ÝÌõ¼þ²éÕÒµ¥¸öʵÌå</summary>
        /// <param name="whereClause">²éѯÌõ¼þ</param>
        /// <returns></returns>
        [DataObjectMethod(DataObjectMethodType.Select, false)]
        public static TEntity Find(String whereClause)
        {
            IList<TEntity> list = FindAll(whereClause, null, null, 0, 1);
            if (list == null || list.Count < 1)
                return null;
            else
                return list[0];
        }

        /// <summary>¸ù¾ÝÖ÷¼ü²éÕÒµ¥¸öʵÌå</summary>
        /// <param name="key">ΨһÖ÷¼üµÄÖµ</param>
        /// <returns></returns>
        [DataObjectMethod(DataObjectMethodType.Select, false)]
        public static TEntity FindByKey(Object key)
        {
            FieldItem field = Meta.Unique;
            if (field == null) throw new ArgumentNullException("Meta.Unique", "FindByKey·½·¨ÒªÇó¸Ã±íÓÐΨһÖ÷¼ü£¡");

            // Ψһ¼üΪ×ÔÔöÇÒ²ÎÊýСÓÚµÈÓÚ0ʱ£¬·µ»Ø¿Õ
            if (Helper.IsNullKey(key)) return null;

            return Find(field.Name, key);
        }

        /// <summary>¸ù¾ÝÖ÷¼ü²éѯһ¸öʵÌå¶ÔÏóÓÃÓÚ±íµ¥±à¼­</summary>
        /// <param name="key">ΨһÖ÷¼üµÄÖµ</param>
        /// <returns></returns>
        [DataObjectMethod(DataObjectMethodType.Select, false)]
        public static TEntity FindByKeyForEdit(Object key)
        {
            FieldItem field = Meta.Unique;
            if (field == null) throw new ArgumentNullException("Meta.Unique", "FindByKeyForEdit·½·¨ÒªÇó¸Ã±íÓÐΨһÖ÷¼ü£¡");

            // ²ÎÊýΪ¿Õʱ£¬·µ»ØÐÂʵÀý
            if (key == null)
            {
                //IEntityOperate factory = EntityFactory.CreateOperate(Meta.ThisType);
                return Meta.Factory.Create(true) as TEntity;
            }

            Type type = field.Type;

            // Ψһ¼üΪ×ÔÔöÇÒ²ÎÊýСÓÚµÈÓÚ0ʱ£¬·µ»ØÐÂʵÀý
            if (Helper.IsNullKey(key))
            {
                if (Helper.IsIntType(type) && !field.IsIdentity && DAL.Debug) DAL.WriteLog("{0}µÄ{1}×Ö¶ÎÊÇÕûÐÍÖ÷¼ü£¬ÄãÊÇ·ñÍü¼ÇÁËÉèÖÃ×ÔÔö£¿", Meta.TableName, field.ColumnName);

                return Meta.Factory.Create(true) as TEntity;
            }

            // ´ËÍ⣬һÂÉ·µ»Ø ²éÕÒÖµ£¬¼´Ê¹¿ÉÄÜÊÇ¿Õ¡£¶ø¾ø²»ÄÜÔÚÕÒ²»µ½Êý¾ÝµÄÇé¿öϸøËü·µ»Ø¿Õ£¬ÒòΪ¿ÉÄÜÊÇÕÒ²»µ½Êý¾Ý¶øÒÑ£¬¶ø·µ»ØÐÂʵÀý»áµ¼ÖÂÇ°¶ËÒÔΪÕâÀïÊÇÐÂÔöÊý¾Ý
            TEntity entity = Find(field.Name, key);

            // ÅжÏʵÌå
            if (entity == null)
            {
                String msg = null;
                if (Helper.IsNullKey(key))
                    msg = String.Format("²ÎÊý´íÎó£¡ÎÞ·¨È¡µÃ±àºÅΪ{0}µÄ{1}£¡¿ÉÄÜδÉèÖÃ×ÔÔöÖ÷¼ü£¡", key, Meta.Table.Description);
                else
                    msg = String.Format("²ÎÊý´íÎó£¡ÎÞ·¨È¡µÃ±àºÅΪ{0}µÄ{1}£¡", key, Meta.Table.Description);

                throw new XCodeException(msg);
            }

            return entity;
        }
        #endregion

        #region ¾²Ì¬²éѯ
        /// <summary>»ñÈ¡ËùÓÐʵÌå¶ÔÏó¡£»ñÈ¡´óÁ¿Êý¾Ýʱ»á·Ç³£Âý£¬É÷ÓÃ</summary>
        /// <returns>ʵÌåÊý×é</returns>
        [DataObjectMethod(DataObjectMethodType.Select, false)]
        public static EntityList<TEntity> FindAll()
        {
            return FindAll(null, null, null, 0, 0);
            //return FindAll(String.Format("Select * From {0}", Meta.FormatName(Meta.TableName)));
        }

        /// <summary>
        /// ²éѯ²¢·µ»ØʵÌå¶ÔÏ󼯺ϡ£
        /// ×î¾­µäµÄÅúÁ¿²éѯ£¬¿´Õâ¸öSelect @selects From Table Where @whereClause Order By @orderClause Limit @startRowIndex,@maximumRows£¬Äã¾ÍÃ÷°×¸÷²ÎÊýµÄÒâ˼ÁË¡£
        /// </summary>
        /// <param name="whereClause">Ìõ¼þ£¬²»´øWhere</param>
        /// <param name="orderClause">ÅÅÐò£¬²»´øOrder By</param>
        /// <param name="selects">²éѯÁÐ</param>
        /// <param name="startRowIndex">¿ªÊ¼ÐУ¬0±íʾµÚÒ»ÐÐ</param>
        /// <param name="maximumRows">×î´ó·µ»ØÐÐÊý£¬0±íʾËùÓÐÐÐ</param>
        /// <returns>ʵÌ弯</returns>
        [DataObjectMethod(DataObjectMethodType.Select, false)]
        public static EntityList<TEntity> FindAll(String whereClause, String orderClause, String selects, Int32 startRowIndex, Int32 maximumRows)
        {
            #region º£Á¿Êý¾Ý²éѯÓÅ»¯
            // º£Á¿Êý¾Ýβҳ²éѯÓÅ»¯
            // ÔÚº£Á¿Êý¾Ý·ÖÒ³ÖУ¬È¡Ô½ÊǺóÃæÒ³µÄÊý¾ÝÔ½Âý£¬¿ÉÒÔ¿¼Âǵ¹ÐòµÄ·½Ê½
            // Ö»ÓÐÔÚ°ÙÍòÊý¾Ý£¬ÇÒ¿ªÊ¼ÐдóÓÚÎåÊ®Íòʱ²ÅʹÓÃ
            //Int32 count = Meta.Count;
            //if (startRowIndex > 500000 && count > 1000000)

            // ÈçÏÂÓÅ»¯£¬±ÜÃâÁËÿ´Î¶¼µ÷ÓÃMeta.Count¶øµ¼ÖÂÐγÉÒ»´Î²éѯ£¬ËäÈ»Õâ´Î²éѯʱ¼äËðºÄ²»´ó
            // µ«ÊǾø´ó¶àÊý²éѯ£¬¶¼²»ÐèÒª½øÐÐÀàËƵĺ£Á¿Êý¾ÝÓÅ»¯£¬ÏÔÈ»£¬Õâ¸östartRowIndex½«»áµ²×¡99%ÒÔÉϵÄÀË·Ñ
            Int64 count = 0;
            if (startRowIndex > 500000 && (count = Meta.LongCount) > 1000000)
            {
                // ¼ÆËã±¾´Î²éѯµÄ½á¹ûÐÐÊý
                if (!String.IsNullOrEmpty(whereClause)) count = FindCount(whereClause, orderClause, selects, startRowIndex, maximumRows);
                // ÓαêÔÚÖмäÆ«ºó
                if (startRowIndex * 2 > count)
                {
                    String order = orderClause;
                    Boolean bk = false; // ÊÇ·ñÌø¹ý

                    #region ÅÅÐòµ¹Ðò
                    // ĬÈÏÊÇ×ÔÔö×ֶεĽµÐò
                    FieldItem fi = Meta.Unique;
                    if (String.IsNullOrEmpty(order) && fi != null && fi.IsIdentity) order = fi.Name + " Desc";

                    if (!String.IsNullOrEmpty(order))
                    {
                        String[] ss = order.Split(',');
                        StringBuilder sb = new StringBuilder();
                        foreach (String item in ss)
                        {
                            String fn = item;
                            String od = "asc";

                            Int32 p = fn.LastIndexOf(" ");
                            if (p > 0)
                            {
                                od = item.Substring(p).Trim().ToLower();
                                fn = item.Substring(0, p).Trim();
                            }

                            switch (od)
                            {
                                case "asc":
                                    od = "desc";
                                    break;
                                case "desc":
                                    //od = "asc";
                                    od = null;
                                    break;
                                default:
                                    bk = true;
                                    break;
                            }
                            if (bk) break;

                            if (sb.Length > 0) sb.Append(", ");
                            sb.AppendFormat("{0} {1}", fn, od);
                        }

                        order = sb.ToString();
                    }
                    #endregion

                    // ûÓÐÅÅÐòµÄʵÔÚ²»ÊʺÏÕâÖÖ°ì·¨£¬ÒòΪû°ì·¨µ¹Ðò
                    if (!String.IsNullOrEmpty(order))
                    {
                        // ×î´ó¿ÉÓÃÐÐÊý¸ÄΪʵ¼Ê×î´ó¿ÉÓÃÐÐÊý
                        Int32 max = (Int32)Math.Min(maximumRows, count - startRowIndex);
                        //if (max <= 0) return null;
                        if (max <= 0) return new EntityList<TEntity>();
                        Int32 start = (Int32)(count - (startRowIndex + maximumRows));

                        var builder2 = CreateBuilder(whereClause, order, selects, start, max);
                        EntityList<TEntity> list = LoadData(Meta.Query(builder2, start, max));
                        if (list == null || list.Count < 1) return list;
                        // ÒòΪÕâÑùÈ¡µÃµÄÊý¾ÝÊǵ¹¹ýÀ´µÄ£¬ËùÒÔÕâÀïÐèÒªÔÙµ¹Ò»´Î
                        list.Reverse();
                        return list;
                    }
                }
            }
            #endregion

            var builder = CreateBuilder(whereClause, orderClause, selects, startRowIndex, maximumRows);
            return LoadData(Meta.Query(builder, startRowIndex, maximumRows));
        }

        /// <summary>¸ù¾ÝÊôÐÔÁбíÒÔ¼°¶ÔÓ¦µÄÖµÁÐ±í£¬»ñÈ¡ËùÓÐʵÌå¶ÔÏó</summary>
        /// <param name="names">ÊôÐÔÁбí</param>
        /// <param name="values">ÖµÁбí</param>
        /// <returns>ʵÌåÊý×é</returns>
        public static EntityList<TEntity> FindAll(String[] names, Object[] values)
        {
            // ÅжÏ×ÔÔöºÍÖ÷¼ü
            if (names != null && names.Length == 1)
            {
                FieldItem field = Meta.Table.FindByName(names[0]);
                if (field != null && (field.IsIdentity || field.PrimaryKey))
                {
                    // Ψһ¼üΪ×ÔÔöÇÒ²ÎÊýСÓÚµÈÓÚ0ʱ£¬·µ»Ø¿Õ
                    if (Helper.IsNullKey(values[0])) return null;
                }
            }

            return FindAll(MakeCondition(names, values, "And"), null, null, 0, 0);
        }

        /// <summary>¸ù¾ÝÊôÐÔÒÔ¼°¶ÔÓ¦µÄÖµ£¬»ñÈ¡ËùÓÐʵÌå¶ÔÏó</summary>
        /// <param name="name">ÊôÐÔ</param>
        /// <param name="value">Öµ</param>
        /// <returns>ʵÌåÊý×é</returns>
        [DataObjectMethod(DataObjectMethodType.Select, false)]
        public static EntityList<TEntity> FindAll(String name, Object value) { return FindAll(new String[] { name }, new Object[] { value }); }

        /// <summary>¸ù¾ÝÊôÐÔÒÔ¼°¶ÔÓ¦µÄÖµ£¬»ñÈ¡ËùÓÐʵÌå¶ÔÏó</summary>
        /// <param name="name">ÊôÐÔ</param>
        /// <param name="value">Öµ</param>
        /// <param name="startRowIndex">¿ªÊ¼ÐУ¬0±íʾµÚÒ»ÐÐ</param>
        /// <param name="maximumRows">×î´ó·µ»ØÐÐÊý£¬0±íʾËùÓÐÐÐ</param>
        /// <returns>ʵÌåÊý×é</returns>
        [Obsolete("Çë¸ÄÓÃFindAllByName£¡Õâ¸öFindAll¸ú5²ÎÊýÄǸöÌ«ÈÝÒ׸ã»ìÁË£¬º¦È˲»Ç³£¡")]
        [DataObjectMethod(DataObjectMethodType.Select, false)]
        public static EntityList<TEntity> FindAll(String name, Object value, Int32 startRowIndex, Int32 maximumRows) { return FindAllByName(name, value, null, startRowIndex, maximumRows); }

        /// <summary>¸ù¾ÝÊôÐÔÒÔ¼°¶ÔÓ¦µÄÖµ£¬»ñÈ¡ËùÓÐʵÌå¶ÔÏó</summary>
        /// <param name="name">ÊôÐÔ</param>
        /// <param name="value">Öµ</param>
        /// <param name="orderClause">ÅÅÐò£¬²»´øOrder By</param>
        /// <param name="startRowIndex">¿ªÊ¼ÐУ¬0±íʾµÚÒ»ÐÐ</param>
        /// <param name="maximumRows">×î´ó·µ»ØÐÐÊý£¬0±íʾËùÓÐÐÐ</param>
        /// <returns>ʵÌåÊý×é</returns>
        [DataObjectMethod(DataObjectMethodType.Select, true)]
        public static EntityList<TEntity> FindAllByName(String name, Object value, String orderClause, Int32 startRowIndex, Int32 maximumRows)
        {
            if (String.IsNullOrEmpty(name)) return FindAll(null, orderClause, null, startRowIndex, maximumRows);

            FieldItem field = Meta.Table.FindByName(name);
            if (field != null && (field.IsIdentity || field.PrimaryKey))
            {
                // Ψһ¼üΪ×ÔÔöÇÒ²ÎÊýСÓÚµÈÓÚ0ʱ£¬·µ»Ø¿Õ
                if (Helper.IsNullKey(value)) return new EntityList<TEntity>();

                // ×ÔÔö»òÕßÖ÷¼ü²éѯ£¬¼Ç¼¼¯¿Ï¶¨ÊÇΨһµÄ£¬²»ÐèÒªÖ¸¶¨¼Ç¼ÊýºÍÅÅÐò
                //return FindAll(MakeCondition(field, value, "="), null, null, 0, 0);
                var builder = new SelectBuilder();
                builder.Table = Meta.FormatName(Meta.TableName);
                builder.Where = MakeCondition(field, value, "=");
                return FindAll(builder.ToString());
            }

            return FindAll(MakeCondition(new String[] { name }, new Object[] { value }, "And"), orderClause, null, startRowIndex, maximumRows);
        }

        /// <summary>²éѯSQL²¢·µ»ØʵÌå¶ÔÏóÊý×é¡£
        /// Select·½·¨½«Ö±½ÓʹÓòÎÊýÖ¸¶¨µÄ²éѯÓï¾ä½øÐвéѯ£¬²»½øÐÐÈκÎת»»¡£
        /// </summary>
        /// <param name="sql">²éѯÓï¾ä</param>
        /// <returns>ʵÌåÊý×é</returns>
        public static EntityList<TEntity> FindAll(String sql) { return LoadData(Meta.Query(sql)); }
        #endregion

        #region »ñÈ¡²éѯSQL
        /// <summary>»ñÈ¡²éѯSQL¡£Ö÷ÒªÓÃÓÚ¹¹Ôì×Ó²éѯ</summary>
        /// <param name="whereClause">Ìõ¼þ£¬²»´øWhere</param>
        /// <param name="orderClause">ÅÅÐò£¬²»´øOrder By</param>
        /// <param name="selects">²éѯÁÐ</param>
        /// <param name="startRowIndex">¿ªÊ¼ÐУ¬0±íʾµÚÒ»ÐÐ</param>
        /// <param name="maximumRows">×î´ó·µ»ØÐÐÊý£¬0±íʾËùÓÐÐÐ</param>
        /// <returns>ʵÌ弯</returns>
        public static SelectBuilder FindSQL(String whereClause, String orderClause, String selects, Int32 startRowIndex = 0, Int32 maximumRows = 0)
        {
            var builder = CreateBuilder(whereClause, orderClause, selects, startRowIndex, maximumRows, false);
            return Meta.DBO.PageSplit(builder, startRowIndex, maximumRows);
        }

        /// <summary>»ñÈ¡²éѯΨһ¼üµÄSQL¡£±ÈÈçSelect ID From Table</summary>
        /// <param name="whereClause"></param>
        /// <returns></returns>
        public static SelectBuilder FindSQLWithKey(String whereClause = null)
        {
            var f = Meta.Unique;
            return FindSQL(whereClause, null, f != null ? Meta.FormatName(f.ColumnName) : null, 0, 0);
        }
        #endregion

        #region ¸ß¼¶²éѯ
        /// <summary>²éѯÂú×ãÌõ¼þµÄ¼Ç¼¼¯£¬·ÖÒ³¡¢ÅÅÐò</summary>
        /// <param name="key">¹Ø¼ü×Ö</param>
        /// <param name="orderClause">ÅÅÐò£¬²»´øOrder By</param>
        /// <param name="startRowIndex">¿ªÊ¼ÐУ¬0±íʾµÚÒ»ÐÐ</param>
        /// <param name="maximumRows">×î´ó·µ»ØÐÐÊý£¬0±íʾËùÓÐÐÐ</param>
        /// <returns>ʵÌ弯</returns>
        [DataObjectMethod(DataObjectMethodType.Select, true)]
        public static EntityList<TEntity> Search(String key, String orderClause, Int32 startRowIndex, Int32 maximumRows) { return FindAll(SearchWhereByKeys(key, null), orderClause, null, startRowIndex, maximumRows); }

        /// <summary>²éѯÂú×ãÌõ¼þµÄ¼Ç¼×ÜÊý£¬·ÖÒ³ºÍÅÅÐòÎÞЧ£¬´ø²ÎÊýÊÇÒòΪObjectDataSourceÒªÇóËü¸úSearchͳһ</summary>
        /// <param name="key">¹Ø¼ü×Ö</param>
        /// <param name="orderClause">ÅÅÐò£¬²»´øOrder By</param>
        /// <param name="startRowIndex">¿ªÊ¼ÐУ¬0±íʾµÚÒ»ÐÐ</param>
        /// <param name="maximumRows">×î´ó·µ»ØÐÐÊý£¬0±íʾËùÓÐÐÐ</param>
        /// <returns>¼Ç¼Êý</returns>
        public static Int32 SearchCount(String key, String orderClause, Int32 startRowIndex, Int32 maximumRows) { return FindCount(SearchWhereByKeys(key, null), null, null, 0, 0); }

        /// <summary>¹¹½¨¹Ø¼ü×Ö²éѯÌõ¼þ</summary>
        /// <param name="sb"></param>
        /// <param name="keys"></param>
        public static void SearchWhereByKeys(StringBuilder sb, String keys) { SearchWhereByKeys(sb, keys, null); }

        /// <summary>¹¹½¨¹Ø¼ü×Ö²éѯÌõ¼þ</summary>
        /// <param name="sb"></param>
        /// <param name="keys"></param>
        /// <param name="func"></param>
        public static void SearchWhereByKeys(StringBuilder sb, String keys, Func<String, String> func)
        {
            if (String.IsNullOrEmpty(keys)) return;

            String str = SearchWhereByKeys(keys, func);
            if (String.IsNullOrEmpty(str)) return;

            if (sb.Length > 0) sb.Append(" And ");
            if (str.Contains("Or") || str.ToLower().Contains("or"))
                sb.AppendFormat("({0})", str);
            else
                sb.Append(str);
        }

        /// <summary>¹¹½¨¹Ø¼ü×Ö²éѯÌõ¼þ</summary>
        /// <param name="keys"></param>
        /// <param name="func"></param>
        /// <returns></returns>
        public static String SearchWhereByKeys(String keys, Func<String, String> func)
        {
            if (String.IsNullOrEmpty(keys)) return null;

            if (func == null) func = SearchWhereByKey;

            String[] ks = keys.Split(new Char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < ks.Length; i++)
            {
                if (sb.Length > 0) sb.Append(" And ");

                String str = func(ks[i]);
                if (String.IsNullOrEmpty(str)) continue;

                //sb.AppendFormat("({0})", str);
                if (str.Contains("Or") || str.ToLower().Contains("or"))
                    sb.AppendFormat("({0})", str);
                else
                    sb.Append(str);
            }

            return sb.Length <= 0 ? null : sb.ToString();
        }

        /// <summary>¹¹½¨¹Ø¼ü×Ö²éѯÌõ¼þ</summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public static String SearchWhereByKey(String key)
        {
            StringBuilder sb = new StringBuilder();
            foreach (FieldItem item in Meta.Fields)
            {
                if (item.Type != typeof(String)) continue;

                if (sb.Length > 0) sb.Append(" Or ");
                sb.AppendFormat("{0} like '%{1}%'", Meta.FormatName(item.Name), key);
            }

            return sb.Length <= 0 ? null : sb.ToString();
        }
        #endregion

        #region »º´æ²éѯ
        /// <summary>¸ù¾ÝÊôÐÔÒÔ¼°¶ÔÓ¦µÄÖµ£¬ÔÚ»º´æÖвéÕÒµ¥¸öʵÌå</summary>
        /// <param name="name">ÊôÐÔÃû³Æ</param>
        /// <param name="value">ÊôÐÔÖµ</param>
        /// <returns></returns>
        [DataObjectMethod(DataObjectMethodType.Select, false)]
        public static TEntity FindWithCache(String name, Object value) { return Meta.Cache.Entities.Find(name, value); }

        /// <summary>²éÕÒËùÓлº´æ</summary>
        /// <returns></returns>
        [DataObjectMethod(DataObjectMethodType.Select, false)]
        public static EntityList<TEntity> FindAllWithCache() { return Meta.Cache.Entities; }

        /// <summary>¸ù¾ÝÊôÐÔÒÔ¼°¶ÔÓ¦µÄÖµ£¬ÔÚ»º´æÖлñÈ¡ËùÓÐʵÌå¶ÔÏó</summary>
        /// <param name="name">ÊôÐÔ</param>
        /// <param name="value">Öµ</param>
        /// <returns>ʵÌåÊý×é</returns>
        [DataObjectMethod(DataObjectMethodType.Select, false)]
        public static EntityList<TEntity> FindAllWithCache(String name, Object value) { return Meta.Cache.Entities.FindAll(name, value); }
        #endregion

        #region È¡×ܼǼÊý
        /// <summary>·µ»Ø×ܼǼÊý</summary>
        /// <returns></returns>
        public static Int32 FindCount() { return FindCount(null, null, null, 0, 0); }

        /// <summary>·µ»Ø×ܼǼÊý</summary>
        /// <param name="whereClause">Ìõ¼þ£¬²»´øWhere</param>
        /// <param name="orderClause">ÅÅÐò£¬²»´øOrder By¡£ÕâÀïÎÞÒâÒ壬½ö½öΪÁ˱£³ÖÓëFindAllÏàͬµÄ·½·¨Ç©Ãû</param>
        /// <param name="selects">²éѯÁС£ÕâÀïÎÞÒâÒ壬½ö½öΪÁ˱£³ÖÓëFindAllÏàͬµÄ·½·¨Ç©Ãû</param>
        /// <param name="startRowIndex">¿ªÊ¼ÐУ¬0±íʾµÚÒ»ÐС£ÕâÀïÎÞÒâÒ壬½ö½öΪÁ˱£³ÖÓëFindAllÏàͬµÄ·½·¨Ç©Ãû</param>
        /// <param name="maximumRows">×î´ó·µ»ØÐÐÊý£¬0±íʾËùÓÐÐС£ÕâÀïÎÞÒâÒ壬½ö½öΪÁ˱£³ÖÓëFindAllÏàͬµÄ·½·¨Ç©Ãû</param>
        /// <returns>×ÜÐÐÊý</returns>
        public static Int32 FindCount(String whereClause, String orderClause, String selects, Int32 startRowIndex, Int32 maximumRows)
        {
            var sb = new SelectBuilder();
            sb.Table = Meta.FormatName(Meta.TableName);
            sb.Where = whereClause;

            return Meta.QueryCount(sb);
        }

        /// <summary>¸ù¾ÝÊôÐÔÁбíÒÔ¼°¶ÔÓ¦µÄÖµÁÐ±í£¬·µ»Ø×ܼǼÊý</summary>
        /// <param name="names">ÊôÐÔÁбí</param>
        /// <param name="values">ÖµÁбí</param>
        /// <returns>×ÜÐÐÊý</returns>
        public static Int32 FindCount(String[] names, Object[] values)
        {
            // ÅжÏ×ÔÔöºÍÖ÷¼ü
            if (names != null && names.Length == 1)
            {
                FieldItem field = Meta.Table.FindByName(names[0]);
                if (field != null && (field.IsIdentity || field.PrimaryKey))
                {
                    // Ψһ¼üΪ×ÔÔöÇÒ²ÎÊýСÓÚµÈÓÚ0ʱ£¬·µ»Ø¿Õ
                    if (Helper.IsNullKey(values[0])) return 0;
                }
            }

            return FindCount(MakeCondition(names, values, "And"), null, null, 0, 0);
        }

        /// <summary>¸ù¾ÝÊôÐÔÒÔ¼°¶ÔÓ¦µÄÖµ£¬·µ»Ø×ܼǼÊý</summary>
        /// <param name="name">ÊôÐÔ</param>
        /// <param name="value">Öµ</param>
        /// <returns>×ÜÐÐÊý</returns>
        public static Int32 FindCount(String name, Object value) { return FindCountByName(name, value, null, 0, 0); }

        /// <summary>¸ù¾ÝÊôÐÔÒÔ¼°¶ÔÓ¦µÄÖµ£¬·µ»Ø×ܼǼÊý</summary>
        /// <param name="name">ÊôÐÔ</param>
        /// <param name="value">Öµ</param>
        /// <param name="startRowIndex">¿ªÊ¼ÐУ¬0±íʾµÚÒ»ÐС£ÕâÀïÎÞÒâÒ壬½ö½öΪÁ˱£³ÖÓëFindAllÏàͬµÄ·½·¨Ç©Ãû</param>
        /// <param name="maximumRows">×î´ó·µ»ØÐÐÊý£¬0±íʾËùÓÐÐС£ÕâÀïÎÞÒâÒ壬½ö½öΪÁ˱£³ÖÓëFindAllÏàͬµÄ·½·¨Ç©Ãû</param>
        /// <returns>×ÜÐÐÊý</returns>
        [Obsolete("Çë¸ÄÓÃFindCountByName£¡Õâ¸öFindCount¸ú5²ÎÊýÄǸöÌ«ÈÝÒ׸ã»ìÁË£¬º¦È˲»Ç³£¡")]
        public static Int32 FindCount(String name, Object value, Int32 startRowIndex, Int32 maximumRows) { return FindCountByName(name, value, null, startRowIndex, maximumRows); }

        /// <summary>¸ù¾ÝÊôÐÔÒÔ¼°¶ÔÓ¦µÄÖµ£¬·µ»Ø×ܼǼÊý</summary>
        /// <param name="name">ÊôÐÔ</param>
        /// <param name="value">Öµ</param>
        /// <param name="orderClause">ÅÅÐò£¬²»´øOrder By¡£ÕâÀïÎÞÒâÒ壬½ö½öΪÁ˱£³ÖÓëFindAllÏàͬµÄ·½·¨Ç©Ãû</param>
        /// <param name="startRowIndex">¿ªÊ¼ÐУ¬0±íʾµÚÒ»ÐС£ÕâÀïÎÞÒâÒ壬½ö½öΪÁ˱£³ÖÓëFindAllÏàͬµÄ·½·¨Ç©Ãû</param>
        /// <param name="maximumRows">×î´ó·µ»ØÐÐÊý£¬0±íʾËùÓÐÐС£ÕâÀïÎÞÒâÒ壬½ö½öΪÁ˱£³ÖÓëFindAllÏàͬµÄ·½·¨Ç©Ãû</param>
        /// <returns>×ÜÐÐÊý</returns>
        public static Int32 FindCountByName(String name, Object value, String orderClause, int startRowIndex, int maximumRows)
        {
            if (String.IsNullOrEmpty(name))
                return FindCount(null, null, null, 0, 0);
            else
                return FindCount(new String[] { name }, new Object[] { value });
        }
        #endregion

        #region ¾²Ì¬²Ù×÷
        /// <summary>°ÑÒ»¸öʵÌå¶ÔÏó³Ö¾Ã»¯µ½Êý¾Ý¿â</summary>
        /// <param name="obj">ʵÌå¶ÔÏó</param>
        /// <returns>·µ»ØÊÜÓ°ÏìµÄÐÐÊý</returns>
        [DataObjectMethod(DataObjectMethodType.Insert, true)]
        public static Int32 Insert(TEntity obj) { return obj.Insert(); }

        /// <summary>°ÑÒ»¸öʵÌå¶ÔÏó³Ö¾Ã»¯µ½Êý¾Ý¿â</summary>
        /// <param name="names">¸üÐÂÊôÐÔÁбí</param>
        /// <param name="values">¸üÐÂÖµÁбí</param>
        /// <returns>·µ»ØÊÜÓ°ÏìµÄÐÐÊý</returns>
        public static Int32 Insert(String[] names, Object[] values) { return persistence.Insert(Meta.ThisType, names, values); }

        /// <summary>°ÑÒ»¸öʵÌå¶ÔÏó¸üе½Êý¾Ý¿â</summary>
        /// <param name="obj">ʵÌå¶ÔÏó</param>
        /// <returns>·µ»ØÊÜÓ°ÏìµÄÐÐÊý</returns>
        [DataObjectMethod(DataObjectMethodType.Update, true)]
        public static Int32 Update(TEntity obj) { return obj.Update(); }

        /// <summary>¸üÐÂÒ»ÅúʵÌåÊý¾Ý</summary>
        /// <param name="setClause">Òª¸üеÄÏîºÍÊý¾Ý</param>
        /// <param name="whereClause">Ö¸¶¨Òª¸üеÄʵÌå</param>
        /// <returns></returns>
        public static Int32 Update(String setClause, String whereClause) { return persistence.Update(Meta.ThisType, setClause, whereClause); }

        /// <summary>¸üÐÂÒ»ÅúʵÌåÊý¾Ý</summary>
        /// <param name="setNames">¸üÐÂÊôÐÔÁбí</param>
        /// <param name="setValues">¸üÐÂÖµÁбí</param>
        /// <param name="whereNames">Ìõ¼þÊôÐÔÁбí</param>
        /// <param name="whereValues">Ìõ¼þÖµÁбí</param>
        /// <returns>·µ»ØÊÜÓ°ÏìµÄÐÐÊý</returns>
        public static Int32 Update(String[] setNames, Object[] setValues, String[] whereNames, Object[] whereValues) { return persistence.Update(Meta.ThisType, setNames, setValues, whereNames, whereValues); }

        /// <summary>
        /// ´ÓÊý¾Ý¿âÖÐɾ³ýÖ¸¶¨ÊµÌå¶ÔÏó¡£
        /// ʵÌåÀàÓ¦¸ÃʵÏָ÷½·¨µÄÁíÒ»¸ö¸±±¾£¬ÒÔΨһ¼ü»òÖ÷¼ü×÷Ϊ²ÎÊý
        /// </summary>
        /// <param name="obj">ʵÌå¶ÔÏó</param>
        /// <returns>·µ»ØÊÜÓ°ÏìµÄÐÐÊý£¬¿ÉÓÃÓÚÅжϱ»É¾³ýÁ˶àÉÙÐУ¬´Ó¶øÖªµÀ²Ù×÷ÊÇ·ñ³É¹¦</returns>
        [DataObjectMethod(DataObjectMethodType.Delete, true)]
        public static Int32 Delete(TEntity obj) { return obj.Delete(); }

        /// <summary>´ÓÊý¾Ý¿âÖÐɾ³ýÖ¸¶¨Ìõ¼þµÄʵÌå¶ÔÏó¡£</summary>
        /// <param name="whereClause">ÏÞÖÆÌõ¼þ</param>
        /// <returns></returns>
        public static Int32 Delete(String whereClause) { return persistence.Delete(Meta.ThisType, whereClause); }

        /// <summary>´ÓÊý¾Ý¿âÖÐɾ³ýÖ¸¶¨ÊôÐÔÁбíºÍÖµÁбíËùÏÞ¶¨µÄʵÌå¶ÔÏó¡£</summary>
        /// <param name="names">ÊôÐÔÁбí</param>
        /// <param name="values">ÖµÁбí</param>
        /// <returns></returns>
        public static Int32 Delete(String[] names, Object[] values) { return persistence.Delete(Meta.ThisType, names, values); }

        /// <summary>°ÑÒ»¸öʵÌå¶ÔÏó¸üе½Êý¾Ý¿â</summary>
        /// <param name="obj">ʵÌå¶ÔÏó</param>
        /// <returns>·µ»ØÊÜÓ°ÏìµÄÐÐÊý</returns>
        public static Int32 Save(TEntity obj) { return obj.Save(); }
        #endregion

        #region ¹¹ÔìSQLÓï¾ä
        /// <summary>°ÑSQLÄ£°æ¸ñʽ»¯ÎªSQLÓï¾ä</summary>
        /// <param name="obj">ʵÌå¶ÔÏó</param>
        /// <param name="methodType"></param>
        /// <returns>SQL×Ö·û´®</returns>
        [Obsolete("¸Ã³ÉÔ±ÔÚºóÐø°æ±¾Öн«²»ÔÙ±»Ö§³Ö£¡ÇëʹÓÃXCodeService.Resolve<IEntityPersistence>().GetSql()£¡")]
        public static String SQL(Entity<TEntity> obj, DataObjectMethodType methodType) { return persistence.GetSql(obj, methodType); }

        /// <summary>
        /// ¸ù¾ÝÊôÐÔÁбíºÍÖµÁÐ±í£¬¹¹Ôì²éѯÌõ¼þ¡£
        /// ÀýÈç¹¹Ôì¶àÖ÷¼üÏÞÖƲéѯÌõ¼þ¡£
        /// </summary>
        /// <param name="names">ÊôÐÔÁбí</param>
        /// <param name="values">ÖµÁбí</param>
        /// <param name="action">ÁªºÏ·½Ê½</param>
        /// <returns>Ìõ¼þ×Ó´®</returns>
        public static String MakeCondition(String[] names, Object[] values, String action)
        {
            //if (names == null || names.Length <= 0) throw new ArgumentNullException("names", "ÊôÐÔÁбíºÍÖµÁÐ±í²»ÄÜΪ¿Õ");
            //if (values == null || values.Length <= 0) throw new ArgumentNullException("values", "ÊôÐÔÁбíºÍÖµÁÐ±í²»ÄÜΪ¿Õ");
            if (names == null || names.Length <= 0) return null;
            if (values == null || values.Length <= 0) return null;
            if (names.Length != values.Length) throw new ArgumentException("ÊôÐÔÁбí±ØÐëºÍÖµÁбíÒ»Ò»¶ÔÓ¦");

            StringBuilder sb = new StringBuilder();
            for (Int32 i = 0; i < names.Length; i++)
            {
                FieldItem fi = Meta.Table.FindByName(names[i]);
                if (fi == null) throw new ArgumentException("Àà[" + Meta.ThisType.FullName + "]Öв»´æÔÚ[" + names[i] + "]ÊôÐÔ");

                // ͬʱ¹¹ÔìSQLÓï¾ä¡£namesÊÇÊôÐÔÁÐ±í£¬±ØÐëת»»³É¶ÔÓ¦µÄ×Ö¶ÎÁбí
                if (i > 0) sb.AppendFormat(" {0} ", action.Trim());
                //sb.AppendFormat("{0}={1}", Meta.FormatName(fi.ColumnName), Meta.FormatValue(fi, values[i]));
                sb.Append(MakeCondition(fi, values[i], "="));
            }
            return sb.ToString();
        }

        /// <summary>¹¹ÔìÌõ¼þ</summary>
        /// <param name="name">Ãû³Æ</param>
        /// <param name="value">Öµ</param>
        /// <param name="action">´óÓÚСÓڵȷûºÅ</param>
        /// <returns></returns>
        public static String MakeCondition(String name, Object value, String action)
        {
            FieldItem field = Meta.Table.FindByName(name);
            if (field == null) return String.Format("{0}{1}{2}", Meta.FormatName(name), action, Meta.FormatValue(name, value));

            return MakeCondition(field, value, action);
        }

        /// <summary>¹¹ÔìÌõ¼þ</summary>
        /// <param name="field">Ãû³Æ</param>
        /// <param name="value">Öµ</param>
        /// <param name="action">´óÓÚСÓڵȷûºÅ</param>
        /// <returns></returns>
        public static String MakeCondition(FieldItem field, Object value, String action)
        {
            if (!String.IsNullOrEmpty(action) && action.Contains("{0}"))
            {
                if (action.Contains("%"))
                    return Meta.FormatName(field.ColumnName) + " Like " + Meta.FormatValue(field, String.Format(action, value));
                else
                    return Meta.FormatName(field.ColumnName) + String.Format(action, Meta.FormatValue(field, value));
            }
            else
                return String.Format("{0}{1}{2}", Meta.FormatName(field.ColumnName), action, Meta.FormatValue(field, value));
        }

        /// <summary>
        /// ĬÈÏÌõ¼þ¡£
        /// ÈôÓбêʶÁУ¬ÔòʹÓÃÒ»¸ö±êʶÁÐ×÷ΪÌõ¼þ£»
        /// ÈçÓÐÖ÷¼ü£¬ÔòʹÓÃÈ«²¿Ö÷¼ü×÷ΪÌõ¼þ¡£
        /// </summary>
        /// <param name="obj">ʵÌå¶ÔÏó</param>
        /// <returns>Ìõ¼þ</returns>
        [Obsolete("¸Ã³ÉÔ±ÔÚºóÐø°æ±¾Öн«²»ÔÙ±»Ö§³Ö£¡ÇëʹÓÃXCodeService.Resolve<IEntityPersistence>().GetPrimaryCondition()£¡")]
        protected static String DefaultCondition(Entity<TEntity> obj) { return persistence.GetPrimaryCondition(obj); }

        static SelectBuilder CreateBuilder(String whereClause, String orderClause, String selects, Int32 startRowIndex, Int32 maximumRows, Boolean needOrderByID = true)
        {
            var builder = new SelectBuilder();
            builder.Column = selects;
            builder.Table = Meta.FormatName(Meta.TableName);
            builder.OrderBy = orderClause;
            // ½÷¼Ç£ºÄ³Ð©ÏîÄ¿ÖпÉÄÜÔÚwhereÖÐʹÓÃÁËGroupBy£¬ÔÚ·Öҳʱ¿ÉÄܱ¨´í
            builder.Where = whereClause;

            // XCode¶ÔÓÚĬÈÏÅÅÐòµÄ¹æÔò£º×ÔÔöÖ÷¼ü½µÐò£¬ÆäËüÇé¿öĬÈÏ
            // ·µ»ØËùÓмǼ
            if (!needOrderByID && startRowIndex <= 0 && maximumRows <= 0) return builder;

            FieldItem fi = Meta.Unique;
            if (fi != null)
            {
                builder.Key = Meta.FormatName(fi.ColumnName);

                // ĬÈÏ»ñÈ¡Êý¾Ýʱ£¬»¹ÊÇÐèÒªÖ¸¶¨°´ÕÕ×ÔÔö×ֶνµÐò£¬·ûºÏʹÓÃÏ°¹ß
                // ÓÐGroupByÒ²²»ÄܼÓÅÅÐò
                if (String.IsNullOrEmpty(builder.OrderBy) && String.IsNullOrEmpty(builder.GroupBy))
                {
                    // Êý×Ö½µÐò£¬ÆäËüÉýÐò
                    var b = Helper.IsIntType(fi.Type) && fi.IsIdentity;
                    builder.IsDesc = b;
                    // ÐÞÕýûÓÐÉèÖÃbuilder.IsIntµ¼Ö·ÖҳûÓÐÑ¡Ôñ×î¼ÑµÄMaxMinµÄBUG£¬¸Ðл @RICH(20371423)
                    builder.IsInt = b;

                    builder.OrderBy = builder.KeyOrder;
                }
            }
            else
            {
                // Èç¹ûÕÒ²»µ½Î¨Ò»¼ü£¬²¢ÇÒÅÅÐòÓÖΪ¿Õ£¬Ôò²ÉÓÃÈ«²¿×Ö¶ÎÒ»Æð£¬È·±£Äܹ»·ÖÒ³
                if (String.IsNullOrEmpty(builder.OrderBy)) builder.Keys = Meta.FieldNames.ToArray();
            }
            return builder;
        }
        #endregion

        #region »ñÈ¡/ÉèÖà ×Ö¶ÎÖµ
        /// <summary>
        /// »ñÈ¡/ÉèÖà ×Ö¶ÎÖµ¡£
        /// Ò»¸öË÷Òý£¬·´ÉäʵÏÖ¡£
        /// ÅÉÉúʵÌåÀà¿ÉÖØд¸ÃË÷Òý£¬ÒÔ±ÜÃâ·¢Éä´øÀ´µÄÐÔÄÜËðºÄ¡£
        /// »ùÀàÒѾ­ÊµÏÖÁËͨÓõĿìËÙ·ÃÎÊ£¬µ«ÊÇÕâÀïÈÔÈ»ÖØд£¬ÒÔÔö¼Ó¿ØÖÆ£¬
        /// ±ÈÈç×Ö¶ÎÃûÊÇÊôÐÔÃûÇ°Ãæ¼ÓÉÏ_£¬²¢ÇÒÒªÇóÊÇʵÌå×ֶβÅÔÊÐíÕâÑù·ÃÎÊ£¬·ñÔòÒ»ÂÉ°´ÊôÐÔ´¦Àí¡£
        /// </summary>
        /// <param name="name">×Ö¶ÎÃû</param>
        /// <returns></returns>
        public override Object this[String name]
        {
            get
            {
                //Æ¥Åä×Ö¶Î
                if (Meta.FieldNames.Contains(name))
                {
                    FieldInfoX field = FieldInfoX.Create(this.GetType(), "_" + name);
                    if (field != null) return field.GetValue(this);
                }

                //³¢ÊÔÆ¥ÅäÊôÐÔ
                PropertyInfoX property = PropertyInfoX.Create(this.GetType(), name);
                if (property != null && property.GetMethod != null) return property.GetValue(this);

                Object obj = null;
                if (Extends.TryGetValue(name, out obj)) return obj;

                //throw new ArgumentException("Àà[" + this.GetType().FullName + "]Öв»´æÔÚ[" + name + "]ÊôÐÔ");

                return null;
            }
            set
            {
                //Æ¥Åä×Ö¶Î
                if (Meta.FieldNames.Contains(name))
                {
                    FieldInfoX field = FieldInfoX.Create(this.GetType(), "_" + name);
                    if (field != null)
                    {
                        field.SetValue(this, value);
                        return;
                    }
                }

                //³¢ÊÔÆ¥ÅäÊôÐÔ
                PropertyInfoX property = PropertyInfoX.Create(this.GetType(), name);
                if (property != null && property.SetMethod != null)
                {
                    property.SetValue(this, value);
                    return;
                }

                //foreach (FieldItem fi in Meta.AllFields)
                //    if (fi.Name == name) { fi.Property.SetValue(this, value, null); return; }

                if (Extends.ContainsKey(name))
                    Extends[name] = value;
                else
                    Extends.Add(name, value);

                //throw new ArgumentException("Àà[" + this.GetType().FullName + "]Öв»´æÔÚ[" + name + "]ÊôÐÔ");
            }
        }
        #endregion

        #region µ¼Èëµ¼³öXML
        /// <summary>½¨Á¢XmlÐòÁл¯Æ÷</summary>
        /// <returns></returns>
        //[Obsolete("¸Ã³ÉÔ±ÔÚºóÐø°æ±¾Öн«²»ÔÙ±»Ö§³Ö£¡")]
        protected override XmlSerializer CreateXmlSerializer()
        {
            // ¸øÿһ¸öÊý¾ÝÊôÐÔ¼ÓÉÏXmlĬÈÏÖµÌØÐÔ£¬ÈÃXmlÐòÁл¯Ê±±Ü¿ªÊý¾ÝÓëĬÈÏÖµÏàͬµÄÊý¾ÝÊôÐÔ£¬¼õÉÙXml´óС
            XmlAttributeOverrides ovs = new XmlAttributeOverrides();
            TEntity entity = new TEntity();
            foreach (FieldItem item in Meta.Fields)
            {
                XmlAttributes atts = new XmlAttributes();
                atts.XmlAttribute = new XmlAttributeAttribute();
                atts.XmlDefaultValue = entity[item.Name];
                ovs.Add(item.DeclaringType, item.Name, atts);
            }
            return new XmlSerializer(this.GetType(), ovs);
        }

        /// <summary>µ¼Èë</summary>
        /// <param name="xml"></param>
        /// <returns></returns>
        [Obsolete("¸Ã³ÉÔ±ÔÚºóÐø°æ±¾Öн«²»ÔÙ±»Ö§³Ö£¡")]
        public static TEntity FromXml(String xml)
        {
            if (!String.IsNullOrEmpty(xml)) xml = xml.Trim();

            StopExtend = true;
            try
            {
                //IEntityOperate factory = EntityFactory.CreateOperate(typeof(TEntity));
                XmlSerializer serial = ((TEntity)Meta.Factory.Default).CreateXmlSerializer();
                using (StringReader reader = new StringReader(xml))
                {
                    return serial.Deserialize(reader) as TEntity;
                }
            }
            finally { StopExtend = false; }
        }
        #endregion

        #region µ¼Èëµ¼³öJson
        /// <summary>µ¼Èë</summary>
        /// <param name="json"></param>
        /// <returns></returns>
        [Obsolete("¸Ã³ÉÔ±ÔÚºóÐø°æ±¾Öн«²»ÔÙ±»Ö§³Ö£¡")]
        public static TEntity FromJson(String json)
        {
            return new Json().Deserialize<TEntity>(json);
        }
        #endregion

        #region ¿Ë¡
        /// <summary>´´½¨µ±Ç°¶ÔÏóµÄ¿Ë¡¶ÔÏ󣬽ö¿½±´»ù±¾×Ö¶Î</summary>
        /// <returns></returns>
        public override Object Clone() { return CloneEntity(); }

        /// <summary>¿Ë¡ʵÌå¡£´´½¨µ±Ç°¶ÔÏóµÄ¿Ë¡¶ÔÏ󣬽ö¿½±´»ù±¾×Ö¶Î</summary>
        /// <returns></returns>
        public virtual TEntity CloneEntity(Boolean setDirty = true)
        {
            TEntity obj = CreateInstance();
            foreach (FieldItem fi in Meta.Fields)
            {
                //obj[fi.Name] = this[fi.Name];
                if (setDirty)
                    obj.SetItem(fi.Name, this[fi.Name]);
                else
                    obj[fi.Name] = this[fi.Name];
            }
            if (Extends != null && Extends.Count > 0)
            {
                foreach (String item in Extends.Keys)
                {
                    obj.Extends[item] = Extends[item];
                }
            }
            return obj;
        }

        /// <summary>¿Ë¡ʵÌå</summary>
        /// <param name="setDirty"></param>
        /// <returns></returns>
        internal protected override IEntity CloneEntityInternal(Boolean setDirty = true) { return CloneEntity(setDirty); }
        #endregion

        #region ÆäËü
        /// <summary>ÒÑÖØÔØ¡£</summary>
        /// <returns></returns>
        public override string ToString()
        {
            // ÓÅÏȲÉÓÃÒµÎñÖ÷¼ü£¬Ò²¾ÍÊÇΨһË÷Òý
            IDataTable table = Meta.Table.DataTable;
            if (table.Indexes != null && table.Indexes.Count > 0)
            {
                IDataIndex di = null;
                foreach (IDataIndex item in table.Indexes)
                {
                    if (!item.Unique) continue;
                    if (item.Columns == null || item.Columns.Length < 1) continue;

                    IDataColumn[] columns = table.GetColumns(item.Columns);
                    if (columns == null || columns.Length < 1) continue;

                    di = item;

                    // Èç¹ûÖ»ÓÐÒ»¸öÖ÷¼ü£¬²¢ÇÒÊÇ×ÔÔö£¬ÔÙÍùÏÂÕÒ±ðµÄ¡£Èç¹ûºóÃæʵÔÚÕÒ²»µ½£¬ÖÁÉÙ»¹ÓÐÏÖÔÚÕâ¸ö¡£
                    if (!(columns.Length == 1 && columns[0].Identity)) break;
                }

                if (di != null)
                {
                    IDataColumn[] columns = table.GetColumns(di.Columns);

                    // [v1,v2,...vn]
                    StringBuilder sb = new StringBuilder();
                    foreach (IDataColumn dc in columns)
                    {
                        if (sb.Length > 0) sb.Append(",");
                        if (Meta.FieldNames.Contains(dc.Alias)) sb.Append(this[dc.Alias]);
                    }
                    if (columns.Length > 1)
                        return String.Format("[{0}]", sb.ToString());
                    else
                        return sb.ToString();
                }
            }

            if (Meta.FieldNames.Contains("Name"))
                return this["Name"] == null ? null : this["Name"].ToString();
            else if (Meta.FieldNames.Contains("ID"))
                return this["ID"] == null ? null : this["ID"].ToString();
            else
                return "ʵÌå" + Meta.ThisType.Name;
        }
        #endregion

        #region ÔàÊý¾Ý
        /// <summary>ÉèÖÃËùÓÐÊý¾ÝµÄÔàÊôÐÔ</summary>
        /// <param name="isDirty">¸Ä±äÔàÊôÐÔµÄÊôÐÔ¸öÊý</param>
        /// <returns></returns>
        protected override Int32 SetDirty(Boolean isDirty)
        {
            Int32 count = 0;
            foreach (String item in Meta.FieldNames)
            {
                Boolean b = false;
                if (isDirty)
                {
                    if (!Dirtys.TryGetValue(item, out b) || !b)
                    {
                        Dirtys[item] = true;
                        count++;
                    }
                }
                else
                {
                    if (Dirtys == null || Dirtys.Count < 1) break;
                    if (Dirtys.TryGetValue(item, out b) && b)
                    {
                        Dirtys[item] = false;
                        count++;
                    }
                }
            }
            return count;
        }

        /// <summary>Èç¹û×ֶδøÓÐĬÈÏÖµ£¬ÔòÐèÒªÉèÖÃÔàÊý¾Ý£¬ÒòΪÏÔÈ»Óû§ÏëÉèÖøÃ×ֶΣ¬¶ø²»ÊDzÉÓÃÊý¾Ý¿âµÄĬÈÏÖµ</summary>
        /// <param name="fieldName"></param>
        /// <param name="newValue"></param>
        /// <returns></returns>
        protected override bool OnPropertyChanging(string fieldName, object newValue)
        {
            // Èç¹û·µ»Øtrue£¬±íʾ²»Ïàͬ£¬»ùÀàÒѾ­ÉèÖÃÁËÔàÊý¾Ý
            if (base.OnPropertyChanging(fieldName, newValue)) return true;

            // Èç¹û¸Ã×ֶδæÔÚ£¬ÇÒ´øÓÐĬÈÏÖµ£¬ÔòÐèÒªÉèÖÃÔàÊý¾Ý£¬ÒòΪÏÔÈ»Óû§ÏëÉèÖøÃ×ֶΣ¬¶ø²»ÊDzÉÓÃÊý¾Ý¿âµÄĬÈÏÖµ
            FieldItem fi = Meta.Table.FindByName(fieldName);
            if (fi != null && !String.IsNullOrEmpty(fi.DefaultValue))
            {
                Dirtys[fieldName] = true;
                return true;
            }

            return false;
        }
        #endregion

        #region À©Õ¹ÊôÐÔ
        /// <summary>»ñÈ¡ÒÀÀµÓÚµ±Ç°ÊµÌåÀàµÄÀ©Õ¹ÊôÐÔ</summary>
        /// <typeparam name="TResult">·µ»ØÀàÐÍ</typeparam>
        /// <param name="key">¼ü</param>
        /// <param name="func">»Øµ÷</param>
        /// <returns></returns>
        protected TResult GetExtend<TResult>(String key, Func<String, Object> func) { return GetExtend<TEntity, TResult>(key, func); }

        /// <summary>»ñÈ¡ÒÀÀµÓÚµ±Ç°ÊµÌåÀàµÄÀ©Õ¹ÊôÐÔ</summary>
        /// <typeparam name="TResult">·µ»ØÀàÐÍ</typeparam>
        /// <param name="key">¼ü</param>
        /// <param name="func">»Øµ÷</param>
        /// <param name="cacheDefault">ÊÇ·ñ»º´æĬÈÏÖµ£¬¿ÉÑ¡²ÎÊý£¬Ä¬ÈÏ»º´æ</param>
        /// <returns></returns>
        protected TResult GetExtend<TResult>(String key, Func<String, Object> func, Boolean cacheDefault) { return GetExtend<TEntity, TResult>(key, func, cacheDefault); }

        /// <summary>ÉèÖÃÒÀÀµÓÚµ±Ç°ÊµÌåÀàµÄÀ©Õ¹ÊôÐÔ</summary>
        /// <param name="key">¼ü</param>
        /// <param name="value">Öµ</param>
        protected void SetExtend(String key, Object value) { SetExtend<TEntity>(key, value); }
        #endregion

        #region ÀÛ¼Ó
        [NonSerialized]
        private static ICollection<String> _AdditionalFields;
        /// <summary>ĬÈÏÀÛ¼Ó×Ö¶Î</summary>
        [XmlIgnore]
        protected static ICollection<String> AdditionalFields { get { return _AdditionalFields ?? (_AdditionalFields = new HashSet<String>(StringComparer.OrdinalIgnoreCase)); } }
        #endregion
    }
}