c#自己封装一个轻量级ORM框架FastORM

在日常进行数据库操作的过程中,我的数据层使用的是微软企业库,但对于多字段的数据的插入与更新时写sql语句就会显得特别费时间,还会经常出现错误耗费时间排查,所以决定基于微软企业库封装一个轻量级的ORM框架(基于mysql),来简化数据库操作。

首先解决的问题就是实体类与数据库表的字段映射,这里使用的是反射,先上个代码

 public T ConvertDataToEntity(DataRow row) where T:TModel
        {
            Dictionary dic = new Dictionary();
            DataColumnCollection columns = row.Table.Columns;
            //获取对象类型
            Type tp = typeof(T);
            //获取空构造函数
            ConstructorInfo ct = tp.GetConstructor(System.Type.EmptyTypes);
            //new 对象
            T entity = (T)ct.Invoke(null);
            //获取所有公有字段
            PropertyInfo[] infos = tp.GetProperties();
            //遍历字段进行查询结果的逐个赋值
            foreach (PropertyInfo info in infos)
            {
                dic.Add(info.Name, null);
                if (columns.Contains(info.Name))
                {
                    object fieldvalue = null;
                    //判断查出的值是否为null,不为null才能反射赋值
                    if (!Convert.IsDBNull(row[info.Name]))
                    {
                        fieldvalue = row[info.Name];
                    }
                    else
                    {
                        fieldvalue = info.PropertyType.IsValueType ? Activator.CreateInstance(info.PropertyType) : null;
                    }
                    info.SetValue(entity, fieldvalue);
                    if (dic.Keys.Contains(info.Name))
                    {
                        dic[info.Name] = fieldvalue;
                    }
                    entity.FieldValueMapper = dic;
                }
            }
            return entity;
        }

具体的步骤就是首先获取传入对象类型的Type,获取空的构造函数,调用构造函数new一个对象出来,获取实体类的所有字段和取数据库中的值进行字段匹配赋值,封装的方法中都是使用了泛型,是为了更好的通用性,传入什么对象,映射返回就是什么对象,强类型引用避免了强制转换装箱拆箱的过程。

关于数据库的操作是基于微软企业库的,都封装在了Command对象中,先来看下代码结构

  public class Command
    {
        public Database DB { set; get; }
        public string CommandText { set; get; }
        public List ParamDic { set; get; }
        public ORMEnum.OptionType CommandType { set; get; }
        public DbTransaction CommandTransition { set; get; }
        public MapperUtil Mapper { set; get; }

        public Command()
        {
            Mapper = new MapperUtil();
        }
        public void ExecuteCommand()
        {
            string strSql = (DB.DbProviderFactory.ToString() != "System.Data.OracleClient.OracleClientFactory") ?
            CommandText :
            CommandText;
            DbCommand cmd = DB.GetSqlStringCommand(strSql);
            if (null != ParamDic)
            {
                foreach (Param param in ParamDic)
                {
                    DB.AddInParameter(cmd, param.ParamName, param.ParamType, param.ParamValue);
                }
            }
            DB.ExecuteNonQuery(cmd);
            if (null != CommandTransition)
            {
                DB.ExecuteNonQuery(cmd, CommandTransition);
            }
            else
            {
                DB.ExecuteNonQuery(cmd);
            }
        }


        public List QueryCommand() where T : TModel
        {
   
            List list = new List();
            string strSql = (DB.DbProviderFactory.ToString() != "System.Data.OracleClient.OracleClientFactory") ?
             CommandText :
             CommandText;
            DbCommand cmd = DB.GetSqlStringCommand(strSql);
            if (null != ParamDic)
            {
                foreach (Param param in ParamDic)
                {
                    DB.AddInParameter(cmd, param.ParamName, param.ParamType, param.ParamValue);
                }
            }
            DataView result = DB.ExecuteDataView(cmd);
            foreach (DataRow row in result.Table.Rows)
            {
                T entity = Mapper.ConvertDataToEntity(row);
                list.Add(entity);
            }
            return list;
        }

里面封装了两个比较常用类型的方法,一个是执行数据库操作,例如插入和更新等,一个是查询操作,用来返回映射后的数据对象List。初始化Command对象的工作封装在了BaseCommand类中,返回一个Command对象,再执行Comadn对象的Execute的方法,主要是为了封装事物的执行,耦合度太高会影响后续扩展,下面来看下ORM框架事物是如何实现的。

1.在Command中已经可以看到定义了Transition对象,会根据对象属性判断是否执行事物

2.在对外访问的类DBUtil中我们会封装一个Transition对象,在执行所有方法时会判断这个事物对象是否为空,不为空复制给Command对象的事物成员对象

3.ExecuteTransition方法以Deletegate委托的形式接收用户的操作,并对事物对象初始化,所有的操作就会关联同一个事物

看下ExecuteTransition的代码与用法

 public void ExecuteTransition(TransitionHandler handler, out string exceptionStr)
        {
            exceptionStr = string.Empty;
            using (DbConnection connection = db.CreateConnection())
            {
                connection.Open();
                transaction = connection.BeginTransaction();
                try
                {
                    handler.Invoke();
                    transaction.Commit();
                }
                catch (Exception e)
                {
                    exceptionStr = e.Message + e.StackTrace;
                    transaction.Rollback();
                    throw e;
                }
                finally
                {
                    connection.Close();
                    transaction = null;
                }
            }

        }

c#自己封装一个轻量级ORM框架FastORM_第1张图片

最后说一下对实体类的定义,非常简单,只要和数据库表一致就可以,另外给主键标志为自定义的Attribute,从而可以智能的实现主键查找与删除方法的实现

 public class frame_user:TModel
    {

        [Key]
        public string userguid { set; get; }
        public string loginid { set; get; }
        public string displayname { set; get; }
        public string password { set; get; }
    }

注:框架中还封装了一些常用方法,例如简单的分页查找,批量插入,根据主键查找,直接执行sql,其中事物同时支持sql与ORM操作的混合使用,希望大家多多提意见与交流,我可以进一步完善这个框架,感谢!

更新:最近FastORM加入弱引用类型的简单增删改查对象,对反射使用表达式树优化选项,加入支持lamda表达式的泛型查找方法,框架的具体使用说明已在项目ReadMe中添加

项目源码地址:https://gitee.com/grassprogramming/FastORM

你可能感兴趣的:(c#自己封装一个轻量级ORM框架FastORM)