必须填写至少10个字的日志
nnhy 编写于 2012-07-27 18:48:21
X
using System;
using System.Collections.Generic;
using System.Data;
using NewLife.Reflection;
using XCode.Configuration;
using XCode.DataAccessLayer;

namespace XCode
{
    /// <summary>在数据行和实体类之间映射数据的接口</summary>
    public interface IDataRowEntityAccessor
    {
        /// <summary>加载数据表。无数据时返回空集合而不是null。</summary>
        /// <param name="dt">数据表</param>
        /// <returns>实体数组</returns>
        IEntityList LoadData(DataTable dt);

        /// <summary>从一个数据行对象加载数据。不加载关联对象。</summary>
        /// <param name="dr">数据行</param>
        /// <param name="entity">实体对象</param>
        void LoadData(DataRow dr, IEntity entity);

        /// <summary>从数据读写器加载数据。无数据时返回空集合而不是null。</summary>
        /// <param name="dr">数据读写器</param>
        /// <returns>实体数组</returns>
        IEntityList LoadData(IDataReader dr);

        /// <summary>从一个数据行对象加载数据。不加载关联对象。</summary>
        /// <param name="dr">数据读写器</param>
        /// <param name="entity">实体对象</param>
        void LoadData(IDataReader dr, IEntity entity);

        /// <summary>把数据复制到数据行对象中。</summary>
        /// <param name="entity">实体对象</param>
        /// <param name="dr">数据行</param>
        DataRow ToData(IEntity entity, ref DataRow dr);
    }

    /// <summary>在数据行和实体类之间映射数据接口的提供者</summary>
    public interface IDataRowEntityAccessorProvider
    {
        /// <summary>创建实体类的数据行访问器</summary>
        /// <param name="entityType"></param>
        /// <returns></returns>
        IDataRowEntityAccessor CreateDataRowEntityAccessor(Type entityType);
    }

    class DataRowEntityAccessorProvider : IDataRowEntityAccessorProvider
    {
        /// <summary>创建实体类的数据行访问器</summary>
        /// <param name="entityType"></param>
        /// <returns></returns>
        public IDataRowEntityAccessor CreateDataRowEntityAccessor(Type entityType)
        {
            return new DataRowEntityAccessor(entityType);
        }
    }

    class DataRowEntityAccessor : IDataRowEntityAccessor
    {
        #region 属性
        private Type _EntityType;
        /// <summary>实体类</summary>
        public Type EntityType
        {
            get { return _EntityType; }
            set { _EntityType = value; }
        }

        private IEntityOperate _Factory;
        /// <summary>实体操作者</summary>
        public IEntityOperate Factory
        {
            get { return _Factory ?? (_Factory = EntityFactory.CreateOperate(EntityType)); }
            set { _Factory = value; }
        }

        private Dictionary<String, FieldItem> _FieldItems;
        /// <summary>字段名-字段字典</summary>
        public Dictionary<String, FieldItem> FieldItems
        {
            get
            {
                if (_FieldItems == null)
                {
                    Dictionary<String, FieldItem> dic = new Dictionary<String, FieldItem>(StringComparer.OrdinalIgnoreCase);
                    foreach (FieldItem item in Factory.AllFields)
                    {
                        if (!dic.ContainsKey(item.ColumnName)) dic.Add(item.ColumnName, item);
                    }
                    _FieldItems = dic;
                }
                return _FieldItems;
            }
        }

        public DataRowEntityAccessor(Type type) { EntityType = type; }
        #endregion

        #region 存取
        /// <summary>加载数据表。无数据时返回空集合而不是null。</summary>
        /// <param name="dt">数据表</param>
        /// <returns>实体数组</returns>
        public IEntityList LoadData(DataTable dt)
        {
            //if (dt == null || dt.Rows.Count < 1) return null;

            // 准备好实体列表
            //EntityList<TEntity> list = new EntityList<TEntity>(dt.Rows.Count);
            IEntityList list = TypeX.CreateInstance(typeof(EntityList<>).MakeGenericType(EntityType), dt.Rows.Count) as IEntityList;
            if (dt == null || dt.Rows.Count < 1) return list;

            List<FieldItem> ps = new List<FieldItem>();
            List<String> exts = new List<String>();
            foreach (DataColumn item in dt.Columns)
            {
                String name = item.ColumnName;
                FieldItem fi = null;
                if (FieldItems.TryGetValue(name, out fi))
                    ps.Add(fi);
                else
                    exts.Add(name);
            }

            // 遍历每一行数据,填充成为实体
            foreach (DataRow dr in dt.Rows)
            {
                //TEntity obj = new TEntity();
                // 由实体操作者创建实体对象,因为实体操作者可能更换
                IEntity obj = Factory.Create();
                LoadData(dr, obj, ps, exts);
                list.Add(obj);
            }
            return list;
        }

        /// <summary>从一个数据行对象加载数据。不加载关联对象。</summary>
        /// <param name="dr">数据行</param>
        /// <param name="entity">实体对象</param>
        public void LoadData(DataRow dr, IEntity entity)
        {
            if (dr == null) return;

            List<FieldItem> ps = new List<FieldItem>();
            List<String> exts = new List<String>();
            foreach (DataColumn item in dr.Table.Columns)
            {
                String name = item.ColumnName;
                FieldItem fi = null;
                if (FieldItems.TryGetValue(name, out fi))
                    ps.Add(fi);
                else
                    exts.Add(name);
            }

            LoadData(dr, entity, ps, exts);
        }

        /// <summary>从数据读写器加载数据。无数据时返回空集合而不是null。</summary>
        /// <param name="dr">数据读写器</param>
        /// <returns>实体数组</returns>
        public IEntityList LoadData(IDataReader dr)
        {
            //if (dr == null) return null;

            //// 先移到第一行,要取字段名等信息
            //if (!dr.Read()) return null;

            // 准备好实体列表
            IEntityList list = TypeX.CreateInstance(typeof(EntityList<>).MakeGenericType(EntityType)) as IEntityList;

            if (dr == null) return list;

            // 先移到第一行,要取字段名等信息
            if (!dr.Read()) return list;

            List<FieldItem> ps = new List<FieldItem>();
            List<String> exts = new List<String>();
            for (int i = 0; i < dr.FieldCount; i++)
            {
                String name = dr.GetName(i);
                FieldItem fi = null;
                if (FieldItems.TryGetValue(name, out fi))
                    ps.Add(fi);
                else
                    exts.Add(name);
            }

            // 遍历每一行数据,填充成为实体
            do
            {
                // 由实体操作者创建实体对象,因为实体操作者可能更换
                IEntity entity = Factory.Create();
                foreach (FieldItem item in ps)
                {
                    SetValue(entity, item.Name, item.Type, dr[item]);
                }

                foreach (String item in exts)
                {
                    SetValue(entity, item, null, dr[item]);
                }

                list.Add(entity);
            } while (dr.Read());
            return list;
        }

        /// <summary>从一个数据读写器加载数据。不加载关联对象。</summary>
        /// <param name="dr">数据读写器</param>
        /// <param name="entity">实体对象</param>
        public void LoadData(IDataReader dr, IEntity entity)
        {
            if (dr == null) return;

            // IDataReader的GetSchemaTable方法太浪费资源了
            for (int i = 0; i < dr.FieldCount; i++)
            {
                String name = dr.GetName(i);
                Type type = null;

                FieldItem fi = null;
                if (FieldItems.TryGetValue(name, out fi))
                {
                    name = fi.Name;
                    type = fi.Type;
                }

                SetValue(entity, name, type, dr.GetValue(i));
            }
        }

        /// <summary>把数据复制到数据行对象中。</summary>
        /// <param name="entity">实体对象</param>
        /// <param name="dr">数据行</param>
        public DataRow ToData(IEntity entity, ref DataRow dr)
        {
            if (dr == null) return null;

            List<String> ps = new List<String>();
            foreach (FieldItem fi in Factory.AllFields)
            {
                // 检查dr中是否有该属性的列。考虑到Select可能是不完整的,此时,只需要局部填充
                if (dr.Table.Columns.Contains(fi.ColumnName))
                {
                    dr[fi.ColumnName] = entity[fi.Name];
                }

                ps.Add(fi.ColumnName);
            }

            // 扩展属性也写入
            if (entity.Extends != null && entity.Extends.Count > 0)
            {
                foreach (String item in entity.Extends.Keys)
                {
                    try
                    {
                        if (!ps.Contains(item) && dr.Table.Columns.Contains(item))
                            dr[item] = entity.Extends[item];
                    }
                    catch { }
                }
            }
            return dr;
        }
        #endregion

        #region 方法
        static String[] TrueString = new String[] { "true", "y", "yes", "1" };
        static String[] FalseString = new String[] { "false", "n", "no", "0" };

        private void LoadData(DataRow dr, IEntity entity, List<FieldItem> ps, List<String> exts)
        {
            if (dr == null) return;

            foreach (FieldItem item in ps)
            {
                SetValue(entity, item.Name, item.Type, dr[item]);
            }

            foreach (String item in exts)
            {
                SetValue(entity, item, null, dr[item]);
            }
        }

        private void SetValue(IEntity entity, String name, Type type, Object value)
        {
            // 注意:name并不一定是实体类的成员
            Object oldValue = entity[name];

            if (type == null)
            {
                if (oldValue != null)
                    type = oldValue.GetType();
                else if (value != null)
                    type = value.GetType();
            }

            // 不处理相同数据的赋值
            if (Object.Equals(value, oldValue)) return;

            if (type == typeof(String))
            {
                // 不处理空字符串对空字符串的赋值
                if (value != null && String.IsNullOrEmpty(value.ToString()))
                {
                    if (oldValue == null || String.IsNullOrEmpty(oldValue.ToString())) return;
                }
            }
            else if (type == typeof(Boolean))
            {
                // 处理字符串转为布尔型
                if (value != null && value.GetType() == typeof(String))
                {
                    String vs = value.ToString();
                    if (String.IsNullOrEmpty(vs))
                        value = false;
                    else
                    {
                        if (Array.IndexOf(TrueString, vs.ToLower()) >= 0)
                            value = true;
                        else if (Array.IndexOf(FalseString, vs.ToLower()) >= 0)
                            value = false;
                        else if (DAL.Debug)
                            DAL.WriteLog("无法把字符串{0}转为布尔型!", vs);
                    }
                }
            }
            else if (type == typeof(Guid))
            {
                if (!(value is Guid))
                {
                    if (value is Byte[])
                        value = new Guid((Byte[])value);
                    else if (value is String)
                        value = new Guid((String)value);
                }
            }

            //不影响脏数据的状态
            Boolean? b = null;
            if (entity.Dirtys.ContainsKey(name)) b = entity.Dirtys[name];

            entity[name] = value == DBNull.Value ? null : value;

            if (b != null)
                entity.Dirtys[name] = b.Value;
            else
                entity.Dirtys.Remove(name);
        }

        //DictionaryCache<String, Type> nameTypes = new DictionaryCache<string, Type>();
        //Type GetFieldTypeByName(String name)
        //{
        //    return nameTypes.GetItem(name, delegate(String key)
        //    {
        //        foreach (FieldItem item in Factory.AllFields)
        //        {
        //            if (item.ColumnName == key) return item.Type;
        //        }
        //        return null;
        //    });
        //}
        #endregion
    }
}