首页 > 代码库 > 用基础知识实现数据到模型的填充

用基础知识实现数据到模型的填充

  目前的开发中,我们一般会从数据库查询出来数据,再把数据填充到一个对象中,然后就可以很方便的读取对象信息了。data填充到object这个过程很是繁琐,为简化这个问题,各种框架、组件层出不穷,在此不一一列举,我实在也列举不出 -_- !  诸多框架用起来固然方便,但我总会想起一句话,原文模糊了,出处忘了,大意是“当到一定程度时技术都会以各自的方式失败”,且不说失败不失败,用框架的同学在某个时刻肯定有过这样的感慨:“要是这个框架支持XX就好了”、“这个功能本来很简单,但我们项目现在用的是这个框架,要实现这个功能看来又要写蹩足的代码了”、“这个框架越来越不符合我们的要求,难道我们要改成YY框架吗?”等等。所以框架都有自身固有的限制,那么我们面临的问题,第一时间真的都要求助于框架吗?

本文想表达的决无轻视框架的意思,只是园里讨论框架的甚多,往往让新手有一种不了解、不会用某某框架就说明自己差人一大截的感觉,同时也让很多新手只因会用很多框架就感觉自己很牛B的样子,不管是哪种情况,都不利于自身技术上的提高。所以此文是只是希望新手们能深刻思考一下自己的现状,给自己一个正确的评估,努力做到看到如何调用时,就大概能想象出内部是如何实现的,说白了就是对语言本身很熟悉,对一些思想有了解,下面不表框架的种种,单用新手都知道的技术组合出一个data到object的实现。

准备及问题:

  准备1,数据库test1有表MyUser{

    ID (PK, int, not null)  

    UserName (varchar(20), not null)

    Age (tinyint, not null)

    Birthday (datetime, null)

    }

  准备2,数据库test2有表Message{

    ID (PK, int, not null)

    MyUserID (int, not null)

    Content (nvarchar(200), not null)

    AddTime (datetime, not null)

  }

      准备3,SQLHelper一个,这个自不必说,访问数据库嘛!

  问题1,一个data到object的填充只实现一次,不管是取多少个字段,不管是取一条数据还是多条数据

  问题2,关联查询,为了强调演示,关联数据在不同的数据库里,具体就是查用户和他们的消息(可能用动态和评论来举例更合适,呵呵 谅解!)

 思考:

  想重用,自然而然的就会想到继承;

  想统一处理,也要想到抽象;

  想动态添加数据,要能想到字典,大家一定要记得,字典是一个很好用的数据结构

  想用统一的方法得到不同的具体的类型对象,自然是泛型了。

  下方会一一体现,现在不明所以没关系。

 实现:

  data到object的填充,具体到ado.net,一般就是reader到object了,要实现动态字段都用一个方法填充,以MyUser来说,大概可以这样:

public MessageInfo FillModelFromReader(DbDataReader reader, params string[] fields)
        {
            var info = new MessageInfo();
            if (DALUtil.HasFields("ID", fields)) { info.ID = (int)reader["ID"]; }
            if (DALUtil.HasFields("MyUserID", fields)) { info.MyUserID = (int)reader["MyUserID"]; }
            if (DALUtil.HasFields("Content", fields)) { info.Content = reader["Content"].ToString(); }
            if (DALUtil.HasFields("AddTime", fields)) { info.AddTime = (DateTime)reader["AddTime"]; }
            return info;
        }

   数据库交互无非就那几个方法,我们可以抽象出来一个数据访问的基类,实际运用中还要写几个方法重载,以便于调用

    /// <summary>
    /// DAL基类
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public abstract class DALBase<T>
    {
        /// <summary>
        /// 由子类决定用哪个链接
        /// </summary>
        protected abstract string ConnName
        {
            get;
        }

        protected abstract T FillModelFromReader(DbDataReader reader, params string[] fields);

        protected string GetConnStr()
        {
            return System.Configuration.ConfigurationManager.ConnectionStrings[ConnName].ConnectionString;
        }

        protected List<T> FindList(string sql, CommandType type, params SqlParameter[] parameters)
        {
            using (var reader = SqlHelper.ExecuteReader(GetConnStr(), type, sql, parameters))
            {
                List<T> list = new List<T>();
                var fields = DALUtil.GetReaderFieldNames(reader);
                while (reader.Read())
                {
                    list.Add(FillModelFromReader(reader, fields));
                }
                return list;
            }
        }

        protected T FindOne(string sql, CommandType type, params SqlParameter[] parameters)
        {
            return FindList(sql, type, parameters).FirstOrDefault();
        }

        private List<T> FindPage(string tableName, string fields, string query, string orderby, int pageIndex, int pageSize, bool isTotal, out int totalCount, params SqlParameter[] parameters)
        {
            if (pageIndex < 1)
            {
                throw new ArgumentException("pageIndex参数应>1");
            }

            StringBuilder sb = new StringBuilder();
            SqlParameter[] newPs;
            if (isTotal)
            {
                sb.AppendFormat("select count(0) from [{0}]", tableName);
                if (!string.IsNullOrWhiteSpace(query))
                {
                    sb.AppendFormat(" where {0}", query);
                }
                totalCount = GetCount(sb.ToString(), parameters);
                sb.Clear();
                newPs = SqlHelper.CopyParameters(parameters);
            }
            else
            {
                newPs = parameters;
                totalCount = 0;
            }

            if (string.IsNullOrWhiteSpace(orderby))
            {
                throw new ArgumentException("orderby参数不应为空");
            }

            var fs = string.IsNullOrWhiteSpace(fields) ? "*" : string.Join(",", fields);
            sb.AppendFormat("select {0} from (", fs);
            sb.AppendFormat(" select top {0} {1},ROW_NUMBER() over(order by {2}) rowid from {3}", pageIndex * pageSize, fs, orderby, tableName);
            if (!string.IsNullOrWhiteSpace(query))
            {
                sb.AppendFormat(" where {0}", query);
            }
            sb.AppendFormat(")t where t.rowid>{0} and t.rowid<={1}", (pageIndex - 1) * pageSize, pageIndex * pageSize);

            return FindList(sb.ToString(), CommandType.Text, newPs);
        }

        protected object GetScalar(string sql, CommandType type, params SqlParameter[] parameters)
        {
            return SqlHelper.ExecuteScalar(GetConnStr(), type, sql, parameters);
        }

        protected int GetCount(string sql, CommandType type, params SqlParameter[] parameters)
        {
            var obj = GetScalar(sql, type, parameters);
            if (obj == null) return -1;
            return (int)obj;
        }

        protected int Execute(string sql, CommandType type, params SqlParameter[] parameters)
        {
            return SqlHelper.ExecuteNonQuery(GetConnStr(), type, sql, parameters);
        }
    }
View Code

   实现MyUserDAL,继承于DALBase<MyUserInfo>,设置自己的链接名,实现自己的填充方法,而所有的查询直接调用基类的方法即可,不管哪个查询,都会在基类调用自己实现的填充方法!这样问题1算是解决了。(模型和FillModelFromReader都是用MyGeneration)

public class MyUserDAL : DALBase<MyUserInfo>
    {
        protected override string ConnName
        {
            get { return "sqlconn1"; }
        }

        protected override MyUserInfo FillModelFromReader(DbDataReader reader, params string[] fields)
        {
            var info = new MyUserInfo();
            if (DALUtil.HasFields("ID", fields)) info.ID = (int)reader["ID"];
            if (DALUtil.HasFields("UserName", fields)) info.UserName = reader["UserName"].ToString();
            if (DALUtil.HasFields("Age", fields)) info.Age = (byte)reader["Age"];
            if (DALUtil.HasFields("Birthday", fields) && !(reader["Birthday"] is DBNull)) info.Birthday = (DateTime)reader["Birthday"];
            return info;
        }

        public MyUserInfo FindOne(int id)
        {
            var sql = "select * from MyUser where ID=@id";
            return FindOne(sql, DALUtil.CreateParameter("id", id));
        }

        public List<MyUserInfo> Find1()
        {
            var sql = "select ID,UserName from MyUser";
            return FindList(sql);
        }

        public List<MyUserInfo> Find2()
        {
            var sql = "select ID,UserName,Age,Birthday from MyUser";
            return FindList(sql);
        }
    }

  问题2是表关联问题,这个时候要想到字典,字典这个东西真是再强调也不为过啊。对于UI层,我们取数据是从模型来的,所以关联数据也要在模型上,我们为需要关联数据的模型建一个基类,关联数据其实可以理解为附加数据的一种,所以我们以后叫它附加数据:

    /// <summary>
    /// 模型层附加数据基类
    /// </summary>
    [Serializable]
    public class ModelBase
    {
        private Dictionary<string, object> _exData = http://www.mamicode.com/new Dictionary<string, object>();

        public Dictionary<string, object> ExData
        {
            get { return _exData; }
            set { _exData =http://www.mamicode.com/ value; }
        }

        /// <summary>
        /// 得到附加数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="name"></param>
        /// <returns></returns>
        public T GetExData<T>(string name)
        {
            object data;
            if (_exData.TryGetValue(name, out data))
            {
                return (T)data;
            }
            return default(T);
        }

        /// <summary>
        /// 添加附加数据
        /// </summary>
        /// <param name="name"></param>
        /// <param name="obj"></param>
        public void AddExData(string name, object obj)
        {
            _exData.Add(name, obj);
        }

        /// <summary>
        /// 检测附加数据是否存在
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public bool ExistsExData(string name)
        {
            return _exData.ContainsKey(name);
        }
    }

  MyUserInfo有附加数据,那么就让MyUserInfo继承ModelBase吧,继承后便有了存储附加数据的能力,而附加数据这个操作写到哪里呢?当然是写到BLL里,首先实现Message的相关功能,这里我们需要一个public List<MessageInfo> FindByUserIDs(IEnumerable<int> userids)的方法来根据一串userid得到一个MessageInfo的集合,代码不贴了,下附下载。直接看MyUserBLL里的操作:

    public class MyUserBLL
    {
        DAL.MyUserDAL dal = new DAL.MyUserDAL();

        public MyUserInfo FindOne(int id)
        {
            return dal.FindOne(id);
        }

        public List<MyUserInfo> Find1()
        {
            var list = dal.Find1();
            return list;
        }

        public List<MyUserInfo> Find2()
        {
            var list = dal.Find2();
            DealMsg(list);
            return list;
        }

        static void DealMsg(List<MyUserInfo> list)
        {
            var ids = list.Select(u => u.ID);
            MessageBLL msgbll = new MessageBLL();
            var msgs = msgbll.FindByUserIDs(ids);
            foreach (var info in list)
            {
                info.AddExData("Messages", msgs.Where(msg => msg.MyUserID == info.ID).ToList());
            }
        }
    }

  一个DealMsg方法,便来自两个数据库的数据连接到一起了,像DealXX的方法可以根据需要要以有多个,分别附加不的数据,再看测试:

    class Program
    {
        static MyUserBLL userbll = new MyUserBLL();
        static void Main(string[] args)
        {
            F0();
            Console.WriteLine();
            F1();
            Console.WriteLine();
            F2();
        }

        static void F0()
        {
            var info = userbll.FindOne(2);
            Console.WriteLine(info.ToString());
        }

        static void F1()
        {
            var list = userbll.Find1();
            foreach (var info in list)
            {
                Console.WriteLine(info.ToString());
            }
        }

        static void F2()
        {
            var list = userbll.Find2();
            foreach (var info in list)
            {
                Console.WriteLine(info.ToString());
                var messages = info.GetExData<List<MessageInfo>>("Messages");
                foreach (var msg in messages)
                {
                    Console.WriteLine("\t{0}", msg.ToString());
                }
                Console.WriteLine();

            }
        }
    }

至此收工!

很多简单的东西掌握好了,组合起来也能做一些事件吧!

 下载