反射+Dapper.NET搭建ORM框架

最近在工作过程中发现,还有很多猿在使用动软代码生成器,或者自己手写DAL类,每个表一个DAL类,并且每个DAL都写一堆CRUD的方法,除了表名,字段名不一样,其他的代码基本都是重复的,这完全不符合面向对象编程的特性,并且会造成代码冗余,复用性极低,维护不便等等问题。

下面介绍一种复用性极高的ORM框架 反射+Dapper.Net

关于反射的使用这里不再说了,大家可以去查看我的文章-> 对C# 反射使用的一些整理

Dapper.NET -轻量级ORM,有多轻呢,封装一个DapperHelper类,写好连接字符串就可以调用了,相比Entity Framework这种来处理关系映射的ORM,会发现Dapper.NET既省时又省力。

为什么选择Dapper.NET?

    1、轻量,可复用性极高
    2、速度快。Dapper的速度接近与IDataReader,取列表的数据超过了DataTable。
    3、支持多种数据库。Dapper可以在所有Ado.net Providers下工作,包括sqlite, sqlce, firebird, oracle, MySQL, PostgreSQL and SQL Server
    4、可以映射一对一,一对多,多对多等多种关系。
    5、性能高。通过Emit反射IDataReader的序列队列,来快速的得到和产生对象,性能不错。
    6、支持FrameWork2.0,3.0,3.5,4.0,4.5,4.6,4.7 .......

接下来我们看一下常见的使用Dapper.NET写的BLL和DAL层代码

BLL层 新增Insert方法

       public bool Insert(User model)
        {
            try
            {
              return new UserDAL().Insert(model);

            }
            catch (Exception ex)
            {
              
            }
            return false;
        }

DAL层 新增Insert方法

  public bool Insert(User model, string tableName)
        {
            string sql = "insert into User(name,sex) values(@name,@sex)";
            return dapper.Execute(sql, model);
        }

从上面的代码可以看出相对于传统的ORM框架,使用Dapper.NET后,代码量明显减少了很多,但是复用性太低,如果这么写,那每个数据库表都要建这么一个BLL和DAL类,并且还要把CRUD的方法在重新写一遍。

 

接下来我们把反射应用上去

BLL层 新增Insert方法

        public bool Insert(T model, string tableName)
        {

            try
            {
               return  _baseDAL.Insert(model, tableName)

            }
            catch (Exception ex)
            {
            }
            return false;
        }

DAL层 新增Insert方法

        public bool Insert(T model, string tableName)
        {
            string sqls = $"insert into [{tableName}]({_dapper.GetParas()}) values({_dapper.GetATParas()})";
            return _dapper.Execute(sqls, model);
        }

 DAL层中用到的两个方法

GetParas();  通过反射动态获取 T 对象的所有属性名,假如T为User,属性有Id,Name,Sex,则执行结果为Name,Sex

        public string GetParas()
        {
            StringBuilder columns = new StringBuilder();
            //StringBuilder values = new StringBuilder();
            Type t = typeof(T);
            PropertyInfo[] properties = t.GetProperties();
            foreach (var p in properties)
            {
                if (p.PropertyType.Name == "IList`1" || p.PropertyType.Name.ToUpper().Contains("LIST") || p.Name.ToUpper() == "ID")
                {
                    continue;
                }
                columns.Append(p.Name).Append(",");
            }
            return columns.Remove(columns.Length - 1, 1).ToString();
        }

GetATParas();  通过反射动态获取 T 对象的所有@+属性名,假如T为User,属性有Id,Name,Sex,则执行结果为@Name,@Sex 

        public string GetATParas()
        {
            StringBuilder columns = new StringBuilder();
            //StringBuilder values = new StringBuilder();
            Type t = typeof(T);
            PropertyInfo[] properties = t.GetProperties();
            foreach (var p in properties)
            {
                if (p.PropertyType.Name == "IList`1" || p.PropertyType.Name.ToUpper().Contains("LIST") || p.Name.ToUpper() == "ID")
                {
                    continue;
                }
                columns.Append("@").Append(p.Name).Append(",");
            }
            return columns.Remove(columns.Length - 1, 1).ToString();
        }

最后DAL层Insert方法的sql值为 insert into User(Name,Sex) values(@Name,@Sex);

使用反射的好处显而易见,我们不需要知道传入的对象是谁,你随便传,我把对象拿过来直接解析出你所有的属性,然后拼接成sql执行就完事了。

 

接下来我们在扩展几个简单的CRUD方法,然后把封装成Base类,然后作为父类给其他子类使用,其他子类只需要继承Base类就可以了

BaseBLL类

        _baseDAL = new BaseDAL();

        /// 
        /// 公共全部查询方法
        /// 
        /// 
        /// 
        /// 
        /// 
        public virtual List SelectAll(string where, string tableName)
        {
            try
            {
                List lists = _baseDAL.SelectAll(where, tableName);
                return lists;
            }
            catch (Exception ex)
            {
               
            }
            return null;
        }

        /// 
        /// 公共新增方法
        /// 
        /// 
        /// 
        /// 
        public bool Insert(T model, string tableName)
        {

            try
            {
               return  _baseDAL.Insert(model, tableName)

            }
            catch (Exception ex)
            {
            }
            return false;
        }

        /// 
        /// 公共更新方法
        /// 
        /// 
        /// 
        /// 
        public virtual bool Update(T model, string tableName)
        {
            try
            {
               return _baseDAL.Update(model, tableName);
            }
            catch (Exception ex)
            {
                
            }
            return false;
        } 

        /// 
        /// 公共删除方法
        /// 
        /// 
        /// 
        /// 
        public virtual bool Del(T model, string tableName)
        {
            try
            {
               return _baseDAL.Del(model, tableName);
            }
            catch (Exception ex)
            {
                
            }
            return false;
        }       

BaseDAL类

        _dapper = new DapperHelper();

        /// 
        /// 公共全部查询方法
        /// 
        /// 
        /// 
        /// 
        /// 
        public List SelectAll(string where, string tableName)
        {
            string sql = $"select * from [{tableName}] where 1=1";
            if (!string.IsNullOrEmpty(where))
            {
                sql += $" and {where}";
            }
            return _dapper.Query(sql).ToList();
        }

        /// 
        /// 公共新增方法
        /// 
        /// 表类
        /// 对象
        /// 表名
        /// 插入成功true 否则false
        public bool Insert(T model, string tableName)
        {
            string sqls = $"insert into [{tableName}]({_dapper.GetParas()}) values({_dapper.GetATParas()})";
            return _dapper.Execute(sqls, model);
        }

        /// 
        /// 公共更新方法
        /// 
        /// 表类
        /// 对象
        /// 表明
        /// 插入成功true 否则false
        public bool Update(T model, string tableName)
        {
            string sql = $"update [{tableName}] set {_dapper.GetParasToAT()} where Id=@Id";
            return _dapper.Execute(sql, model);
        }
        
        /// 
        /// 公共删除方法
        /// 
        /// 表类
        /// 对象
        /// 表明
        /// 插入成功true 否则false
        public bool Del(T model, string tableName)
        {
            string sql = $"delete [{tableName}] where Id=@Id";
            return _dapper.Execute(sql, model);
        }

DapperHelper

public class DapperHelper
    {
        /// 
        /// the dapper option
        /// 
        private DapperOptions _dapperOptions;
        public DapperHelper(string key = "", DapperOptions dapper = null)
        {
            if (dapper == null)
            {
                dapper = new DapperOptions();
                dapper.ConnectionString = ConfigurationManager.ConnectionStrings["constr"].ToString();
            }
            this._dapperOptions = dapper;
        }

        /// 
        /// get the connection
        /// 
        /// 
        private SqlConnection OpenConnection()
        {
            SqlConnection conn = new SqlConnection(_dapperOptions.ConnectionString);
            conn.Open();
            return conn;
        }         

        /// 
        /// 返回对象属性名称(name)去除标记id name,name,name
        /// 
        /// 
        /// 
        public string GetParas()
        {
            StringBuilder columns = new StringBuilder();
            //StringBuilder values = new StringBuilder();
            Type t = typeof(T);
            PropertyInfo[] properties = t.GetProperties();
            foreach (var p in properties)
            {
                if (p.PropertyType.Name == "IList`1" || p.PropertyType.Name.ToUpper().Contains("LIST") || p.Name.ToUpper() == "ID")
                {
                    continue;
                }
                columns.Append(p.Name).Append(",");
            }
            return columns.Remove(columns.Length - 1, 1).ToString();
        }

        /// 
        /// 返回对象属性名称(@name) @name,@name,@name
        /// 
        /// 类型
        /// 
        public string GetATParas()
        {
            StringBuilder columns = new StringBuilder();
            //StringBuilder values = new StringBuilder();
            Type t = typeof(T);
            PropertyInfo[] properties = t.GetProperties();
            foreach (var p in properties)
            {
                if (p.PropertyType.Name == "IList`1" || p.PropertyType.Name.ToUpper().Contains("LIST") || p.Name.ToUpper() == "ID")
                {
                    continue;
                }
                columns.Append("@").Append(p.Name).Append(",");
            }
            return columns.Remove(columns.Length - 1, 1).ToString();
        }
        /// 
        /// 返回 name=@name, name=@name, name=@name
        /// 
        /// 
        /// 
        public string GetParasToAT()
        {
            StringBuilder columns = new StringBuilder();
            //StringBuilder values = new StringBuilder();
            Type t = typeof(T);
            PropertyInfo[] properties = t.GetProperties();
            foreach (var p in properties)
            {
                if (p.PropertyType.Name == "IList`1" || p.PropertyType.Name.ToUpper().Contains("LIST") || p.Name.ToUpper() == "ID")
                {
                    continue;
                }
                columns.Append(p.Name).Append("=@" + p.Name + ",");
            }
            return columns.Remove(columns.Length - 1, 1).ToString();
        }

        public string GetParasToAT(T model)
        {
            StringBuilder columns = new StringBuilder();
            //StringBuilder values = new StringBuilder();
            Type t = typeof(T);
            PropertyInfo[] properties = t.GetProperties();
            foreach (var p in properties)
            {
                if (p.PropertyType.Name == "IList`1" || p.PropertyType.Name.ToUpper().Contains("LIST") || p.Name.ToUpper() == "ID")
                {
                    continue;
                }
                object value = p.GetValue(model, null);
                if (!string.IsNullOrEmpty(value?.ToString()))
                {
                    columns.Append(p.Name).Append("=@" + p.Name + ",");
                }
            }
            return columns.Remove(columns.Length - 1, 1).ToString();
        }        

        /// 
        /// exec using T-SQL
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public bool Execute(string sql, object param = null, IDbTransaction transaction = null,
            int? commandTimeout = null, CommandType commandType = CommandType.Text)
        {
            using (IDbConnection conn = OpenConnection())
            {
                int count = conn.Execute(sql, param, transaction, commandTimeout, commandType);
                return count > 0;
            }
        }

        public bool ExecuteTran(string sql, object param = null, IDbTransaction transaction = null,
            int? commandTimeout = null, CommandType commandType = CommandType.Text)
        {
            using (IDbConnection conn = OpenConnection())
            {
                transaction = conn.BeginTransaction();
                int count = conn.Execute(sql, param, transaction, commandTimeout, commandType);
                transaction.Commit();
                return count > 0;
            }
        }

        /// 
        /// exec using stored procedure
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public bool ExecuteForProc(string storedProcedureName, object param = null, IDbTransaction transaction = null,
            int? commandTimeout = null, CommandType commandType = CommandType.StoredProcedure)
        {
            using (IDbConnection conn = OpenConnection())
            {
                int count = conn.Execute(storedProcedureName, param, transaction, commandTimeout, commandType);
                return count > 0;
            }
        }

        /// 
        /// query using T-SQL 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public IList Query(string sql, object param = null, IDbTransaction transaction = null,
            bool buffered = true, int? commandTimeout = null, CommandType commandType = CommandType.Text)
        {
            using (IDbConnection conn = OpenConnection())
            {
                return conn.Query(sql, param, transaction, buffered, commandTimeout, commandType).ToList();
            }
        }

        /// 
        /// query using stored procedure
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public IList QueryForProc(string storedProcedureName, object param = null, IDbTransaction transaction = null,
            bool buffered = true, int? commandTimeout = null, CommandType commandType = CommandType.StoredProcedure)
        {
            using (IDbConnection conn = OpenConnection())
            {
                return conn.Query(storedProcedureName, param, transaction, buffered, commandTimeout, commandType).ToList();
            }
        }

        /// 
        /// dynamic query using sql 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public dynamic Query(string sql, object param = null, IDbTransaction transaction = null,
            bool buffered = true, int? commandTimeout = null, CommandType commandType = CommandType.Text)
        {
            using (IDbConnection conn = OpenConnection())
            {
                return conn.Query(sql, param, transaction, buffered, commandTimeout, commandType).ToList();
            }
        }

        /// 
        /// dynamic query using stored procedure
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public dynamic QueryForProc(string storedProcedureName, object param = null, IDbTransaction transaction = null,
           bool buffered = true, int? commandTimeout = null, CommandType commandType = CommandType.StoredProcedure)
        {
            using (IDbConnection conn = OpenConnection())
            {
                return conn.Query(storedProcedureName, param, transaction, buffered, commandTimeout, commandType).ToList();
            }
        }

        /// 
        /// 批量插入功能
        /// 
        public void InsertBatch(IEnumerable entityList, string tblName, IDbTransaction transaction = null) where T : class
        {
            tblName = tblName ?? string.Format("dbo.{0}", typeof(T).Name);
            var tran = (SqlTransaction)transaction;
            using (var bulkCopy = new SqlBulkCopy(OpenConnection() as SqlConnection, SqlBulkCopyOptions.TableLock, tran))
            {
                bulkCopy.BatchSize = entityList.Count();
                bulkCopy.DestinationTableName = tblName;
                var table = new DataTable();
                ISqlGenerator sqlGenerator = new SqlGeneratorImpl(new DapperExtensionsConfiguration());
                var classMap = sqlGenerator.Configuration.GetMap();
                var props = classMap.Properties.Where(x => x.Ignored == false).ToArray();
                foreach (var propertyInfo in props)
                {
                    bulkCopy.ColumnMappings.Add(propertyInfo.Name, propertyInfo.Name);
                    table.Columns.Add(propertyInfo.Name, Nullable.GetUnderlyingType(propertyInfo.PropertyInfo.PropertyType) ?? propertyInfo.PropertyInfo.PropertyType);
                }
                var values = new object[props.Count()];
                foreach (var itemm in entityList)
                {
                    for (var i = 0; i < values.Length; i++)
                    {
                        values[i] = props[i].PropertyInfo.GetValue(itemm, null);
                    }
                    table.Rows.Add(values);
                }
                bulkCopy.WriteToServer(table);
            }
        }

        /// 
        /// 批量更新数据(每批次5000)
        /// 
        /// 数据库链接字符串
        /// 
        public bool MultiUpdateData(List list, string tableName)
        {
            DataTable table = ToDataTable(list);
            table.TableName = tableName;
            using (SqlConnection conn = OpenConnection())
            {
                SqlCommand comm = conn.CreateCommand();
                comm.CommandTimeout = 60;
                comm.CommandType = CommandType.Text;
                comm.CommandText = $"select top 1 * from {tableName}";
                SqlDataAdapter adapter = new SqlDataAdapter(comm);
                SqlCommandBuilder commandBulider = new SqlCommandBuilder(adapter);
                commandBulider.ConflictOption = ConflictOption.OverwriteChanges;
                commandBulider.SetAllValues = true;
                foreach (DataRow dr in table.Rows)
                {
                    if (dr.RowState == DataRowState.Unchanged)
                        dr.SetModified();
                }

                try
                {
                    if (conn.State == ConnectionState.Closed)
                    {
                        conn.Open();
                    }
                    //设置批量更新的每次处理条数
                    adapter.UpdateBatchSize = 5000;
                    adapter.SelectCommand.Transaction = conn.BeginTransaction();/////////////////开始事务
                    if (table.ExtendedProperties["SQL"] != null)
                    {
                        adapter.SelectCommand.CommandText = table.ExtendedProperties["SQL"].ToString();
                    }


                    int nCount = adapter.Update(table);
                    adapter.SelectCommand.Transaction.Commit();/////提交事务
                    return nCount > 0;
                }
                catch (Exception ex)
                {
                    if (adapter.SelectCommand != null && adapter.SelectCommand.Transaction != null)
                    {
                        adapter.SelectCommand.Transaction.Rollback();
                    }
                    LogManager.Error("更新失败", ex);
                    return false;
                }
                finally
                {
                    conn.Close();
                    conn.Dispose();
                }
            }
        }

        /// 
        /// List To DataTable
        /// 
        /// 
        /// 
        /// 
        /// 
        public static DataTable ToDataTable(IList list, params string[] propertyName)
        {
            List propertyNameList = new List();
            if (propertyName != null)
            {
                propertyNameList.AddRange(propertyName);
            }
            DataTable result = new DataTable();
            if (list.Count > 0)
            {
                PropertyInfo[] propertys = list[0].GetType().GetProperties();
                foreach (PropertyInfo pi in propertys)
                {
                    if (propertyNameList.Count == 0)
                    {
                        Type colType = pi.PropertyType;
                        if (colType.IsGenericType && colType.GetGenericTypeDefinition() == typeof(Nullable<>))
                        {
                            colType = colType.GetGenericArguments()[0];
                        }
                        result.Columns.Add(pi.Name, colType);
                    }
                    else
                    {
                        if (propertyNameList.Contains(pi.Name))
                        {
                            result.Columns.Add(pi.Name, pi.PropertyType);
                        }
                    }
                }
                for (int i = 0; i < list.Count; i++)
                {
                    ArrayList tempList = new ArrayList();
                    foreach (PropertyInfo pi in propertys)
                    {
                        if (propertyNameList.Count == 0)
                        {
                            object obj = pi.GetValue(list[i], null);
                            tempList.Add(obj);
                        }
                        else
                        {
                            if (propertyNameList.Contains(pi.Name))
                            {
                                object obj = pi.GetValue(list[i], null);
                                tempList.Add(obj);
                            }
                        }
                    }
                    object[] array = tempList.ToArray();
                    result.LoadDataRow(array, true);
                }
            }
            return result;
        }
    }

DapperOptions类

    public class DapperOptions
    {
        /// 
        /// 连接字符串
        /// 
        public string ConnectionString { get; set; }
    }

上面只是简单的CRUD方法,大家可以根据这个思路,自己探索吧!!

你可能感兴趣的:(C#反射的使用)