使用ORM、反射、泛型书写通用的增删改查方法

来源:互联网 发布:php 数组长度 编辑:程序博客网 时间:2024/05/16 19:08

想做这个事情的原因:

公司因为升级系统的原因将WCF作为整个系统的中间部分,负责连接数据库传递数据的工作。而这个任务落到了我的头上。

在使用ORM(CHLOE)的过程中,发现一个问题,就是每一个表如果要实现增删改查的话都需要写一个相应的方法。这是一个重复到极点的工作,是我不能忍受的事情。于是想通过ORM实现通用型的增删改查工作,减轻负担。只需要增加表类,不需要增加SQL语句。

这个项目中我用的是chole

先订立一个目标:
增删改查都只需要写一个方法,增加ORM表类的同时立刻能够使用这几个方法完成增删改查的操作!

为了完成这个目标需要解决的问题:

1、如何在不知道类对象是什么的情况下获得属性的值;

2、如何做到传递一个类,让方法知道它的条件和更新字段;

3、如果做到更新时,只更新可以更新的属性

解决问题1:
使用反射获得对象类的属性和值,typeof().getpropertys()

解决问题2:
在类中增加两个List字段,一个存储Where属性,一个存储Update属性,类型为List

解决问题3:
增加一个在程序运行的过程中不变的字符串数组,存储可更新字段

解决的代码如下:

    /// <summary>    /// 所有表的基类,主要用来区分条件和更新的属性    /// </summary>    public class TableBase    {        [JsonProperty]//让jsonconvert在执行转换的时候,转换这两个内部变量        private List<string> ListWhere { get { return _listW; } set { _listW = value; } }//保存条件的属性名称        private List<string> _listW = new List<string>();        [JsonProperty]        private List<string> ListUpdate { get { return _listU; } set { _listU = value; } }//保存更改的属性名称        private List<string> _listU = new List<string>();        private int _isWhereOrUpdate = 0;//是否条件,为0既不是更新也不是条件        /// <summary>        /// 设置接下来赋值的属性不写入_listWhere和_listUpdate        /// </summary>        public void SetNothing()        {            _isWhereOrUpdate = 0;        }        /// <summary>        /// 设置接下来赋值的属性是条件        /// </summary>        public void SetWhere()        {            _isWhereOrUpdate = 1;        }        /// <summary>        /// 设置接下来赋值的属性是更新值        /// </summary>        public void SetUpdate()        {            _isWhereOrUpdate = 2;        }        /// <summary>        /// 返回条件属性队列        /// </summary>        /// <returns></returns>        public List<string> GetListWhere()        {            return ListWhere;        }        /// <summary>        /// 返回更新属性队列        /// </summary>        /// <returns></returns>        public List<string> GetListUpdate()        {            return ListUpdate;        }        /// <summary>        /// 将修改的数据增加到List中,注意此方法会将原来保存在LIST中的数据删除        /// </summary>        /// <param name="value">属性名称</param>        /// <param name="update">更新的列名</param>        public void AddP(string value, string[] update)        {            for (int i = 0; i < ListUpdate.Count; i++)//时间复杂度O(2n-index)            {                if (ListUpdate[i] == value)                {                    ListUpdate.RemoveAt(i);                }            }            for (int i = 0; i < ListWhere.Count; i++)//时间复杂度O(2n-index)            {                if (ListWhere[i] == value)                {                    ListWhere.RemoveAt(i);                }            }            //添加数据到List中            if (_isWhereOrUpdate == 1)            {                ListWhere.Add(value);            }            else if (_isWhereOrUpdate == 2 && update != null && update.Contains(value))  //如果是能更新的字段            {                ListUpdate.Add(value);            }        }        /// <summary>        /// 清空更新和条件队列        /// </summary>        public void Clear()        {            ListWhere.Clear();            ListUpdate.Clear();        }        /// <summary>        /// 获得set方法所在的属性名称        /// 若使用release版本,frame.GetMethod()获取的是执行的方法,不会获取类中的方法。        /// release中会获取如TestSelect*()的方法,Debug获取SetProperity方法        /// </summary>        /// <returns>返回属性名称</returns>        public string GetPN()        {            StackTrace trace = new StackTrace(true);            StackFrame frame = trace.GetFrame(1);//1代表上级,2代表上上级,以此类推            MethodBase method = frame.GetMethod();            //获得当前方法名称            //Console.WriteLine(memberName);            try            {                var property = (from f in method.DeclaringType.GetProperties()                                where f.GetSetMethod() == method || f.GetGetMethod() == method                                select f).FirstOrDefault();                return property.Name;            }            catch            {                return null;            }        }    }

上面的代码主要解决了获取属性名称、保存更新List和条件List的问题。能够更新的字段放在每一个Table表当中。

数据库表类结构如下图所示:

    public class T_TRACK : TableBase    {        private static readonly string[] UPDATE = {"SFZMHM" };//能够更新的字段        public string SFZMHM { get { return _sfzmhm; } set { _sfzmhm = value; AddP(GetPN(), UPDATE); } }        private string _sfzmhm;        public string TESTDATE { get { return _testdate; } set { _testdate = value; AddP(GetPN(), UPDATE); } }        private string _testdate;        public int? KSCS { get { return _kscs; } set { _kscs = value; AddP(GetPN(), UPDATE); } }        private int? _kscs;        public string DATA { get { return _data; } set { _data = value; AddP(GetPN(), UPDATE); } }        private string _data;    }

上面的代码展示的是一个表的结构,其中UPDATE字段存储了此表可以由客户端更新的字段名称,如果为空的话表示客户端不能更新任何字段。

既然获得属性和值得问题解决了,那么现在就可以利用ORM和上面的TABLE内容写通用的更新代码了。如下:

        /// <summary>        /// 获得当前ListWhere或者ListUpdate的对象的属性        /// </summary>        /// <typeparam name="T"></typeparam>        /// <param name="value"></param>        /// <returns>返回PropertyInfo的列表</returns>        private static List<PropertyInfo> GetPropertys<T>(T value, bool isWhere = true) where T : TableBase        {            //直接利用基类得到listStr            List<string> ListPropertyStr = null;            if (isWhere)                ListPropertyStr = value.GetListWhere();            else                ListPropertyStr = value.GetListUpdate();            //如果不能获得List的话,返回空            if (ListPropertyStr == null || ListPropertyStr.Count == 0)            {                return null;            }            //使用属性方法获得变量值,原来的方法是先获得所有属性,接着判断属性是否在listStr中            List<PropertyInfo> listProperty = new List<PropertyInfo>();//属性            for (int i = 0; i < ListPropertyStr.Count; i++)            {                listProperty.Add(typeof(T).GetProperty(ListPropertyStr[i]));            }            return listProperty;        }        /// <summary>        /// 通用型数据更新方        /// </summary>        /// <typeparam name="T">表类</typeparam>        /// <param name="value">表类实体</param>        /// <returns></returns>        public static int UpdateData<T>(T value) where T : TableBase        {            List<PropertyInfo> listWhereP = GetPropertys(value);            List<PropertyInfo> listUpdateP = GetPropertys(value, false);            //如果没有相应的属性的话,返回空            if (listWhereP == null || listUpdateP == null || listWhereP.Count == 0 || listUpdateP.Count == 0)            {                return 0;            }            int updateRes = 0;//返回结果            //更新语句            try            {                OracleContext context = new OracleContext(new OracleConnectionFactory(GetConnectionStr()));                //查询SQL语句与变量                DbParam[] paras = new DbParam[listWhereP.Count + listUpdateP.Count];//SQL变量保存的地方                //update                string sql = "update " + typeof(T).Name + " set ";                for (int i = 0; i < listUpdateP.Count - 1; i++)                {                    sql += listUpdateP[i].Name + " = " + " :U" + i + ", ";                    paras[i] = DbParam.Create(":U" + i, listUpdateP[i].GetValue(value, null));                }                sql += listUpdateP[listUpdateP.Count - 1].Name + " = " + " :U" + (listUpdateP.Count - 1) + " where ";                paras[listUpdateP.Count - 1] = DbParam.Create(":U" + (listUpdateP.Count - 1), listUpdateP[listUpdateP.Count - 1].GetValue(value, null));                //where                for (int i = 0; i < listWhereP.Count - 1; i++)                {                    sql += listWhereP[i].Name + " = " + " :W" + i + " AND ";                    paras[i + listUpdateP.Count] = DbParam.Create(":W" + i, listWhereP[i].GetValue(value, null));                }                sql += listWhereP[listWhereP.Count - 1].Name + " = " + " :W" + (listWhereP.Count - 1);                paras[listWhereP.Count - 1 + listUpdateP.Count] = DbParam.Create(":W" + (listWhereP.Count - 1), listWhereP[listWhereP.Count - 1].GetValue(value, null));                //查询SQL语句的执行之处                updateRes = context.Session.ExecuteNonQuery(sql, paras);                context.Dispose();                return updateRes;            }            catch (Exception ex)            {                LogHelper.WriteLogWcf(ex.Message, "UpdateData()");                throw new Exception(ex.Message);            }        }

比较遗憾的地方是通用型的方法依旧使用了SQL语句,并没有利用到ORM的易用性。但目前我还没有想到更符合更简洁的方案。

另外一点说明是关于TableBase类中SetWhere(),SetUpdate(),SetNothing()三个方法。

主要含义和命名方式一个意思,在使用了SetWhere()后,后面赋值的属性自动定义为条件,使用SetUpdate()后,后面赋值的属性定义为更新字段,SetNothing后,后面赋值的属性不做定义,主要用于写入数据。

调用的代码如下:

T_TRACK track=new T_TRACK();track.SetWhere();track.KSCS=2;track.SetUpdate();track.SFZMHM="1202222211111111233";UpdateData(track);

这就是通用性更新、查询、删除、插入的思路和方案。

原创粉丝点击