一直以来都有一个梦想,想用更少的代码实现更多的功能。也在一些任职的公司看到过他们内部使用的一些ORM,确实很好很强大,但是个人觉得涉及知识面比较广,不适合个人的理解和使用。最近突发奇想,想自己尝试下,借助一些思路,自己写一个简单的、入门级的框架,所以便有了此文。此文这是一个雏形,实现了一个简单的查询效果,当然如果理解了,那么其他操作都是重复性的了(增加、删除、修改)。
一些问题(仅针对本人)
1、如果采用刚入门的三层,代码量太大,虽然可以使用一些工具来生成(T4等)。但是想实现动态查询的参数化还是比较麻烦的,而且代码重用性不高,几乎每个文件实现的都是一模一样的一些方法。
2、SQL的注入,本人以前的一些代码就存在这样的问题。
3、当然还有些问题就不在这里讲了,以前用过三层的就知道了。
解决
1、个人思路是把整个数据访问全部剥离处理,根据不同的实体,对不同的表进行操作。数据访问层中的方法全是公用的,传入参数和实体(T)。即所有实体公用一个数据访问层,不再像三层那样一个实体,一个数据访问类。
2、将对数据的所有操作全部封装成参数话查询(本文的IN操作没有参数化)。
3、对业务逻辑的处理全部采用面向对象的形式操作。
代码实例
1、动态的构造查询语句参数化及参数列表
private StringBuilder whereString;//SQL查询条件 private Dictionary<string, object> paramTable;//SQL参数列表 private int KeyNum = 1;//参数标识 private string tableName;//表名 private string[] columnNames;//查询列名 /// <summary> /// 构造函数 /// </summary> /// <param name="TableName">表名</param> /// <param name="ColumnNames">列名</param> public SelectString(string TableName, params string[] ColumnNames) { if (paramTable == null) paramTable = new Dictionary<string, object>(); if (whereString == null) { whereString = new StringBuilder(); tableName = TableName; columnNames = ColumnNames; } } /// <summary> /// 获取筛选的列名组成的字符串。 /// </summary> /// <param name="columnNames">筛选的列名集合</param> /// <returns>列名组成的字符串</returns> private string GetColumns() { if (columnNames == null || columnNames.Length == 0) return "*"; string[] cols = new string[columnNames.Length]; for (int i = 0; i < columnNames.Length; i++) { cols[i] = string.Format("{0}", columnNames[i]); } return string.Join(",", cols); } /// <summary> /// and表达式 /// </summary> /// <param name="FieldName">字段名称</param> /// <param name="FieldValue">字段值</param> /// <param name="Operat">操作符</param> public void Add(string FieldName, object FieldValue, string Operat) { if (Operat == "in") whereString.AppendFormat(" and {0} {1} ({2})", FieldName, Operat, FieldValue); else { whereString.AppendFormat(" and {0} {1} {2}", FieldName, Operat, string.Format("@Key{0}", KeyNum)); paramTable.Add(string.Format("@Key{0}", KeyNum), FieldValue); KeyNum++; } } /// <summary> /// or表达式 /// </summary> /// <param name="FieldName">字段名称</param> /// <param name="FieldValue">字段值</param> /// <param name="Operat">操作符</param> public void Or(string FieldName, object FieldValue, string Operat) { if (Operat == "in") whereString.AppendFormat(" or {0} {1} ({2})", FieldName, Operat, FieldValue); else { whereString.AppendFormat(" or {0} {1} {2}", FieldName, Operat, string.Format("@Key{0}", KeyNum)); paramTable.Add(string.Format("@Key{0}", KeyNum), FieldValue); KeyNum++; } } /// <summary> /// SQL参数表 /// </summary> public Dictionary<string, object> ParamsTable { get { return paramTable; } set { paramTable = value; } } /// <summary> /// SQL查询条件 /// </summary> public string QueryString { get { if (whereString.Length > 0) { return string.Format("select {2} from {0} where 1=1 {1}", tableName, whereString, GetColumns()); } else return string.Format("select {1} from {0} where 1=1", tableName, GetColumns()); } }
2、将构造好的参数传入,获取及处理数据,然后返回。
/// <summary> /// 获取数据 /// </summary> /// <param name="Sql">SQL语句</param> /// <param name="paramTable">参数列表</param> /// <returns></returns> public List<T> GetList<T>(string Sql, Dictionary<string, object> paramTable) { List<T> ListT = new List<T>(); using (SqlConnection Connection = new SqlConnection(SqlString)) { Connection.Open(); using (SqlCommand Command = new SqlCommand()) { Command.Connection = Connection; Command.CommandText = Sql; //添加参数 foreach (KeyValuePair<string, object> ItemDictionary in paramTable) { Command.Parameters.Add(new SqlParameter() { ParameterName = ItemDictionary.Key, Value = ItemDictionary.Value }); } SqlDataReader DataReader = Command.ExecuteReader(CommandBehavior.CloseConnection); //反射赋值 PropertyInfo[] propertys = typeof(T).GetProperties(); try { //获取需要返回的列 List<string> ListColumns = DataReader.GetSchemaTable().Rows.Cast<DataRow>().Select(p => p.ItemArray[0].ToString()).ToList(); while (DataReader.Read()) { T t = System.Activator.CreateInstance<T>(); foreach (PropertyInfo item in propertys) { if (ListColumns.Contains(item.Name)) if (DataReader[item.Name] != DBNull.Value) item.SetValue(t, DataReader[item.Name], null); } ListT.Add(t); } } catch (SqlException ex) { throw ex; } finally { //切记关闭 DataReader.Close(); } } } return ListT; }
3、使用(构造实体类)
/// <summary> /// 表名(务必保持与数据库一致) /// </summary> public static string TableName = "Users"; #region 字段名(务必保持与数据库一致) /// <summary> /// 用户编号 /// </summary> public static string C_FUserID = "FUserID"; #endregion #region 属性 /// <summary> /// 用户编号 /// </summary> public int FUserID { get; set; }
使用实例
//实例化查询构造器 SelectString QuerySql = new SelectString(Users.TableName); QuerySql.Add(Users.C_FUserID, 1000, Operat.DengYu); QuerySql.Add(Users.C_UName, "张三", Operat.Like); QuerySql.Or(Users.C_FUserID, "100,110,120,130,140,150,160,170", Operat.In); //获取及填充数据 SqlHelper SqlHelper = new SqlHelper(); List<Users> ListUser = SqlHelper.GetList<Users>(QuerySql.QueryString, QuerySql.ParamsTable);
这里面涉及的知识面也不是特别广,大家应该都能看的懂。其实就是在实体类中多封装一些信息,然后通过一个构造器,构造出需要执行的SQL语句(参数化)和参数集合,然后在传入底层,底层根据传入进来的SQL及参数集合。获取数据,然后再把同时一起传入进来的类型T,根据反射动态赋值,然后再返回上去。这样便简单的实现了一个动态参数化查询,只需要构造好实体类,然后查询构造器,组装好SQL和参数,传入同一个底层方法,即可获取不同表中的数据。此文只说到简单的单表操作,可自行拓展。其他操作都可以照这种思路进行封装哦,把平时需要使用到的一些跟数据库打交道的方法都封装好,然后使用的时候只需要调用就好了。这样是不是使用起来比较方便呢?
到此本文就写完了,其实原理都很简单的,本人只是抱着分享的态度,高手请多多指教。源码将于晚上发布到这里、这里喔(其实源码差不多都在这里了)。
<script type="text/javascript"> </script><script type="text/javascript" src="http://pagead2.googlesyndication.com/pagead/show_ads.js"></script>