C# 编写框架
今天在这里写一套简单的框架,主要用于一些小型的项目,用于数据的增删改查,通用分页查询等操作.所以功能并不强大,而且笔者也是新手,这里面也难免会有bug,忘读者朋友提醒.
现在我们进入正题吧,想要写一套通用的框架,反射是必须要熟知的.至少你需要知道如何通过反射获取属性和值.然后我们自定义一些特性,用于和数据库的连接.
完成框架的制作,我们分步骤来说
1.编写自定义特性
2.通过发射,拼接字符串,用于数据操作
3.完善框架
好,我们先编写自定义特性,创建2.0(因为2.0可以向上兼容,为了实现通用,习惯使用4.0的朋友们,辛苦你们一下了)类库,我的项目名称为ORMAttributes,创建完成之后,我们创建我们的特性,添加cs文件,取名为AttributeTF
这个类需要继承Attribute,首先我们创建特性BindTableAttribute,用于标识类与数据库表之间的关系
1 /// <summary> 2 /// 表特性 3 /// </summary> 4 /// 特性用于class类,一个类中使用只能出现一次 5 /// 6 [AttributeUsage(AttributeTargets.Class, AllowMultiple = false)] 7 public class BindTableAttribute : Attribute 8 { 9 public BindTableAttribute() 10 : base() 11 { 12 13 } 14 15 public BindTableAttribute(string name,Type t) 16 { 17 _name = name; 18 _ct = t; 19 20 new TabelInfo(name,t,ColAdd); 21 } 22 23 private Type _ct; 24 25 public Type Ct 26 { 27 get { return _ct; } 28 set { _ct = value; } 29 } 30 31 private string _name = null; 32 public string name 33 { 34 get { return _name; } 35 } 36 37 private bool _colAdd = false; 38 public bool ColAdd 39 { 40 get { return _colAdd; } 41 set { _colAdd = value; 42 ManageTabel._tabels[_name].ColAdd = value; 43 } 44 } 45 }
_ct:使用记录当前这个类的实体(其实可以不使用,具体原因我后面会说到)
_name:记录名称,也就是用于对应的数据库表名称
_colAdd:是否自动添加列(这是一个辅助的功能,主要用于实体类添加字段后,对应的数据库中是否同样添加列)
接着我们创建BindFiledAttribute,用于标识属性与数据库表中列之间的关系
1 /// <summary> 2 /// 类特性 3 /// </summary> 4 /// 特性作用于属性/字段上.且只能出现一次 5 [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] 6 public class BindFiledAttribute : Attribute 7 { 8 public BindFiledAttribute() 9 : base() 10 { 11 12 } 13 14 public BindFiledAttribute(string name) 15 { 16 _strName = name; 17 } 18 19 private string _strName = null; 20 21 public string StrName 22 { 23 get { return _strName; } 24 } 25 26 27 private string _type = null; 28 29 public string Type 30 { 31 get { return _type; } 32 set { _type = value; } 33 } 34 35 private string _readFormat = null; 36 37 public string ReadFormat 38 { 39 get { return _readFormat; } 40 set { _readFormat = value; } 41 } 42 43 private string _writeFormat = null; 44 45 public string WriteFormat 46 { 47 get { return _writeFormat; } 48 set { _writeFormat = value; } 49 } 50 51 private int _index = -1; 52 53 public int Index 54 { 55 get { return _index; } 56 set { _index = value; } 57 } 58 59 private bool _isKey = false; 60 61 public bool IsKey 62 { 63 get { return _isKey; } 64 set { _isKey = value; 65 } 66 } 67 68 private bool _isIdentity = false; 69 70 public bool IsIdentity 71 { 72 get { return _isIdentity; } 73 set { _isIdentity = value; } 74 } 75 76 }
_strName:表示列的名称
_type:数据类型,例如:varchar(100)...
_readFormat:读取时样式(这个不用在意,笔者发现,这个完全可以返回由程序员自己完成,意义不大)
_writeFormat:保存时样式(同上)
_index:序列号,新增时比较实用,同样可以提高效率(笔者解决了新增时顺序的问题,后面有详细介绍)
_isKey:是否是主键列
is_IsIdentity:是否为自动增涨列
ok,,这样我们的自定义特性也就完成了,,下面我们在model层的实体类上标识下我们所写的特性吧
1 [BindTableAttribute("MyFromWork", typeof(MyFromWork), ColAdd = true)] 2 public class MyFromWork { 3 private int _id; 4 [BindFiledAttribute("id",IsIdentity=true, IsKey = true, Type = "int")] 5 public int Id 6 { 7 get { return _id; } 8 set { _id = value; } 9 } 10 11 private string _name; 12 [BindFiledAttribute("name", Type = "varchar(50)")] 13 public string Name 14 { 15 get { return _name; } 16 set { _name = value; } 17 } 18 19 private string _author; 20 21 [BindFiledAttribute("author", Type = "varchar(50)")] 22 public string Author 23 { 24 get { return _author; } 25 set { _author = value; } 26 } 27 28 private string _remarks; 29 [BindFiledAttribute("remarks", Type = "nvarchar(500)")] 30 public string Remarks 31 { 32 get { return _remarks; } 33 set { _remarks = value; } 34 }
怎么样,是不是很轻松呢,好,我们继续向下说
特性已经出现了,那么我们必定需要有一个地方来存储我们所标识的实体对应的值,所以笔者在这定义了TabelInfo和FileInfo,分别来记录BindTableAttribute和BindFiledAttribute.
public class FileInfo { public FileInfo() : base() { } /// <summary> /// 字段名 /// </summary> private string _strName; public string StrName { get { return _strName; } set { _strName = value; } } /// <summary> /// 数据类型(数据库中) /// </summary> private string _type; public string Type { get { return _type; } set { _type = value; } } /// <summary> /// 展现时字符串样式 /// </summary> private string _readFormat; public string ReadFormat { get { return _readFormat; } set { _readFormat = value; } } /// <summary> /// 保存时字符格式 /// </summary> private string _writeFormat; public string WriteFormat { get { return _writeFormat; } set { _writeFormat = value; } } /// <summary> /// 序列号 /// </summary> private int _index=-1; public int Index { get { return _index; } set { _index = value; } } /// <summary> /// 是否作为条件使用 /// </summary> private bool _isKey; public bool IsKey { get { return _isKey; } set { _isKey = value; } } /// <summary> /// 是否为自动增涨列 /// </summary> private bool _isIdentity; public bool IsIdentity { get { return _isIdentity; } set { _isIdentity = value; } }
public class TabelInfo { #region 属性 //表名 private string _tabelName; public string TabelName { get { return _tabelName; } set { _tabelName = value; } } private Type _type; public Type TabelType { get { return _type; } set { _type = value; } } /// <summary> /// 字段特性 /// </summary> private ArrayList _propretys; public ArrayList Propretys { get { return _propretys; } set { _propretys = value; } } private bool _colAdd = false; public bool ColAdd { get { return _colAdd; } set { _colAdd = value; } } #endregion }
因为笔者希望这些实体类在使用的同时就被记录下来,并被缓存下来,所以笔者有创建了ManageTabel类,用于缓存已被记录的实体类,以及初始化时获取特性等操作
public static class ManageTabel { /// <summary> /// 用于缓存数据 /// </summary> public static IDictionary<string, TabelInfo> _tabels=new Dictionary<string,TabelInfo>(); public static bool IsHave(string key) { return _tabels.ContainsKey(key); } /// <summary> /// 初始化数据 /// </summary> public static void Intital() { foreach (string key in _tabels.Keys) { TabelInfo ti = _tabels[key]; if (ti.Propretys == null) { //获取当前类中的公开属性 PropertyInfo[] pinfo = ti.TabelType.GetProperties(); foreach (PropertyInfo item in pinfo) { object[] attributes = item.GetCustomAttributes(typeof(BindFiledAttribute),false); for (int i = 0; i < attributes.Length; i++) { //获取对应属性值 FileInfo fi = new FileInfo(); BindFiledAttribute ba = attributes[i] as BindFiledAttribute; if(ba!=null) { fi.StrName = ba.StrName; fi.Type = ba.Type; fi.ReadFormat = ba.ReadFormat; fi.WriteFormat = ba.WriteFormat; fi.Index = i; fi.IsIdentity = ba.IsIdentity; fi.IsKey = ba.IsKey; } if (ti.Propretys == null) ti.Propretys = new System.Collections.ArrayList(); ti.Propretys.Add(fi); } } } } } /// <summary> /// 重置 /// </summary> public static void Result() { _tabels.Clear(); } /// <summary> /// 添加数据到集合 /// </summary> /// <param name="key">唯一标识列</param> /// <param name="ti">对象数据</param> /// <returns></returns> public static bool AddObject(string key, TabelInfo ti) { if (IsHave(key)) { throw new Exception("当前数据已存在"); } _tabels.Add(key,ti); return true; } /// <summary> /// 修改数据集 /// </summary> /// <param name="key"></param> /// <param name="ti"></param> /// <returns></returns> public static bool EditeObject(string key, TabelInfo ti) { if (IsHave(key)) { _tabels[key] = ti; return true; } throw new Exception("没有找到您想要替换的数据集"); } /// <summary> /// 删除数据集 /// </summary> /// <param name="key"></param> /// <returns></returns> public static bool RemoveObject(string key) { if (IsHave(key)) { _tabels.Remove(key); return true; } throw new Exception("没有找到您想要删除的数据集"); } }
_tabels用于缓存数据使用,这里的方法和属性都是静态的,就是方便用户随时使用
好了,我们现在回到之前的TabelInfo类,这个类中,我们需要添加一个带参构造
public TabelInfo(string name,Type t,bool colAdd) { _tabelName = name; _type = t; _colAdd = colAdd; if (!ManageTabel.IsHave(name)) { ManageTabel.AddObject(name, this); ManageTabel.Intital(); } }
这里主要是让他起到自动缓存和读取的作用,不至于我们忘记缓存等操作而增加操作
好,现在我们的第一步工作算是完成了,我们进入第二步工作,数据库的连接和数据库操作等
这里我们可以重新创建类库DBUitily.也可以继续在该类库下添加类,笔者比较喜欢分开写所以创建了类库
类库中我们创建类DBSqlServer类,该类主要针对sqlserver而编写的.因为笔者对其他数据库并不是很了解,这里就没有过多的去写了,读者可以自行改写.
这里先写关于数据库的连接字符串,笔者习惯从配置文件中读取该字符串,这里依然从配置文件中读取
private static string CONNECTION = ConfigurationManager.AppSettings["connection"].ToString();
现在编写关于数据库连接操作的一些基本操作
#region 数据库执行 /// <summary> /// 执行新增,删除,修改等语句 /// </summary> /// <param name="txt"></param> /// <returns></returns> public static int ExecuteSql(string txt, CommandType cmdType, params SqlParameter[] paras) { int count = 0; using (SqlConnection conn = new SqlConnection(CONNECTION)) { lock (conn) { try { SqlCommand cmd = new SqlCommand(); CommondPar(conn, cmd, txt, cmdType, null, paras); count = cmd.ExecuteNonQuery(); } catch (Exception) { count = -1; } finally { if (conn.State == ConnectionState.Open) { conn.Close(); conn.Dispose(); } } } return count; } } /// <summary> /// 读取数据 /// </summary> /// <param name="txt"></param> /// <param name="cmdType"></param> /// <param name="paras"></param> /// <returns></returns> public static DataSet ExecuteDataRead(string txt, CommandType cmdType, params SqlParameter[] paras) { DataSet ds = new DataSet(); using (SqlConnection conn = new SqlConnection(CONNECTION)) { lock (conn) { try { SqlCommand cmd = new SqlCommand(); CommondPar(conn, cmd, txt, cmdType, null, paras); using (SqlDataAdapter da = new SqlDataAdapter(txt, conn)) { da.SelectCommand = cmd; da.Fill(ds); } } catch (Exception) { ds = null; } finally { if (conn.State == ConnectionState.Open) { conn.Close(); conn.Dispose(); } } } return ds; } } /// <summary> /// 公用方法 /// </summary> /// <param name="conn">数据库连接</param> /// <param name="cmd">SqlCommand</param> /// <param name="text">sql语句或者存储过程名称</param> /// <param name="cmdType"></param> /// <param name="trans"></param> /// <param name="paras"></param> private static void CommondPar(SqlConnection conn, SqlCommand cmd, string text, CommandType cmdType, SqlTransaction trans, params SqlParameter[] paras) { if (conn == null || cmd == null) throw new Exception("缺少必要参数S去了Connection或者SqlCommand"); else { if (conn.State != ConnectionState.Open) { conn.Open(); } cmd.CommandText = text; cmd.CommandType = cmdType; cmd.Connection = conn; if (trans != null) cmd.Transaction = trans; if (paras != null) cmd.Parameters.AddRange(paras); } } #endregion
如此,我们便可以写创建表和列的字符串了
/// <summary> /// 创建表 /// </summary> /// <param name="ti">数据源</param> /// <returns></returns> private static bool CreateTabel(TabelInfo ti) { StringBuilder sql = new StringBuilder(); sql.AppendLine("CREATE TABLE [" + ti.TabelName + "]("); sql.AppendLine(AddColumns(ti,null,false)); sql.AppendLine(")"); return ExecuteSql(sql.ToString(),CommandType.Text,null)>0?true:false; } /// <summary> /// 添加列 /// </summary> /// <param name="ti">数据源</param> /// <returns></returns> private static string AddColumns(TabelInfo ti, ArrayList list, bool isHave) { StringBuilder sql = new StringBuilder(); int index = 0; //是否是已存在的表 if (isHave) { sql.AppendLine("ALTER TABLE ["+ti.TabelName +"] ADD"); foreach (FileInfo item in ti.Propretys) { if (list.Contains(item.StrName)) { continue; } if (index != 0) sql.AppendLine(","); index++; sql.AppendLine(" [" + item.StrName + "] " + item.Type); } return sql.ToString(); } //表不存在的情况下 bool isKey = true; //主键是否存在,true未出现,false已出现 foreach (FileInfo item in ti.Propretys) { if (index > 0) sql.AppendLine(","); index++; //拼接字符串 sql.AppendLine(" [" + item.StrName + "] " + item.Type); if (item.IsIdentity) sql.AppendLine(" IDENTITY(1,1) "); if (item.IsKey) if (isKey) { sql.AppendLine(" PRIMARY KEY "); isKey = false; } } return sql.ToString(); }
这里,我们需要注意一点小细节
1.表名和列名,我们需要使用"[]"符号括住,防止关键字的出现
2.主键列和自动增涨列的一些标识
因为笔者考虑到,可能有些程序已经存在表了,所以需要创建前要判断下是否存在或者是列是否已存在
/// <summary> /// 检查是否存在表 /// </summary> /// <param name="ti">数据源</param> /// <returns></returns> private static bool IsHaveTabel(TabelInfo ti) { if (ti == null) { throw new Exception("数据源不能为空!"); } StringBuilder sql = new StringBuilder(); sql.AppendLine("SELECT COUNT(name) FROM SYSOBJECTS WHERE XTYPE='U' AND NAME='" + ti.TabelName + "'"); DataSet ds = ExecuteDataRead(sql.ToString(), CommandType.Text); if (ds != null) if (ds.Tables.Count > 0) if (ds.Tables[0].Rows.Count > 0) { //查看数据是否存在 if (Convert.ToInt32(ds.Tables[0].Rows[0][0]) > 0) //存在 return true; } return false; } /// <summary> /// 检查列 /// </summary> /// <param name="ti">数据源</param> /// <returns></returns> private static ArrayList IsHaveCol(TabelInfo ti) { StringBuilder sql = new StringBuilder(); sql.AppendLine("SELECT name FROM SYSCOLUMNS WHERE ID=OBJECT_ID('" + ti.TabelName + "')"); DataSet ds = ExecuteDataRead(sql.ToString(), CommandType.Text, null); if (ds != null) if (ds.Tables.Count > 0) if (ds.Tables[0].Rows.Count > 0) { //存在 ArrayList list = new ArrayList(); foreach (DataRow row in ds.Tables[0].Rows) { list.Add(row[0].ToString()); } return list; } return null; }
ok..这里就已经差不多了,下面,我们需要考虑用户的需求了,可能该用户数据库中已经存在了表,所以不希望框架还重新连接数据库判断是否存在表,这样毕竟还是会消耗资源的,发布后也不希望有这样的操作的.所以笔者在这里创建了一个状态,用于标识
private static bool _ISCREATE; public static bool ISCREATE { get { try { _ISCREATE = ConfigurationManager.AppSettings["auto"].ToString().Equals("1"); } catch (Exception) { _ISCREATE = true; } return DBSqlServer._ISCREATE; } }
同样是从配置文件中读取,如果不存在这样的auto(自动化)节点,则默认自动创建
好,下面就正事创建表的操作了
public static bool CreateTable<T>(Type t,ref TabelInfo ti) { //通过类型,获取名称,从缓存中读取 //隐式创建缓存 object[] obj = t.GetCustomAttributes(typeof(BindTableAttribute), false); foreach (BindTableAttribute item in obj) { if (item == null) continue; string key = item.name; ti = ManageTabel._tabels[key] == null ? ti : ManageTabel._tabels[key]; } if (ti == null) { throw new Exception("数据结构发生异常"); } if (!ISCREATE) return true; //检查数据库中是否存在 if (IsHaveTabel(ti)) { //检查是否存在新的字段需要添加 if (!ti.ColAdd) return false; ArrayList list = IsHaveCol(ti); if (list.Count > 0 && list.Count < ti.Propretys.Count) { //添加列 string sql = AddColumns(ti, list, true); return ExecuteSql(sql, CommandType.Text,null)>0?true:false; } return false; } return CreateTabel(ti); }
这里有这样的一句话
if (!ti.ColAdd) return false;
没错了,这个就是我们之前特性中定义的数据,是否自动添加列,这个作用就是在这里了,如果用户自动添加列,这里会判断用户是否有新增的字段,从而添加到数据库,这里这样的操作,就会避免很多不必要的操作了
这个类算是完成了,因为要自动化的通用增删改查等操作,所以我们还需要一个数据库业务逻辑类,笔者命名为:DBManage
这里的操作主要分为5类,新增,删除,修改,查询,分页;
笔者先说删除与修改;
删除;我们需要的参数有表名,主键列(也就是删除条件)
private bool Delete(string strWhere) { StringBuilder sql = new StringBuilder(); try { sql.AppendLine("DELETE [" + ti.TabelName + "] "); if (string.IsNullOrEmpty(strWhere)) { //条件为空 foreach (PropertyInfo item in ti.TabelType.GetProperties()) { //获取特性,再次验证 object[] objs = item.GetCustomAttributes(typeof(BindFiledAttribute), false); bool fast = true; foreach (BindFiledAttribute bfa in objs) { if (bfa.IsKey) { if (fast) { sql.AppendLine(" WHERE "); fast = false; } sql.AppendLine(" [" + bfa.StrName + "]='" + item.GetValue(model, null) + "'"); } } } return DBSqlServer.ExecuteSql(sql.ToString(), System.Data.CommandType.Text, null) > 0 ? true : false; } else { //按条件查询 sql.AppendLine(" WHERE " + strWhere); return DBSqlServer.ExecuteSql(sql.ToString(), System.Data.CommandType.Text, null) > 0 ? true : false; } } catch (Exception) { return false; } }
这里,参数中我添加了一个条件,这个条件重要是笔者担心业务中有全部删除这一项操作,可能有些人觉得没有这样的必要,但是笔者觉得这样的业务还是可能会出现的,所以留了下来
细心的读者一定会发现,这里有一个主要参数ti,但是却没有看到声明的标记,这里笔者解释下,ti其实是TableInfo的实体对象,因为所有操作都需要,所以笔者已经将其定义为全局变量,方便使用,具体如何实现的,我后面会介绍到,请不要着急,现在只要知道它是TableInfo就可以了
下面我们说说修改,修改与删除几近相同
private bool Edite(string strWhere) { StringBuilder sql = new StringBuilder(); //修改数据,1.是否有自定义条件 if (string.IsNullOrEmpty(strWhere)) { //根据主键修改 sql.AppendLine("UPDATE [" + ti.TabelName + "] SET "); bool fast = true; foreach (PropertyInfo item in ti.TabelType.GetProperties()) { //获取特性,再次验证 object[] objs = item.GetCustomAttributes(typeof(BindFiledAttribute), false); foreach (BindFiledAttribute bfa in objs) { if (bfa.IsKey || bfa.IsIdentity) { strWhere += "["+bfa.StrName + "]='" + item.GetValue(model, null) + "'"; continue; } if (!fast) sql.AppendLine(","); fast = false; sql.AppendLine("[" + bfa.StrName + "]='" + item.GetValue(model, null) + "' "); } } return DBSqlServer.ExecuteSql(sql.ToString() + " where " + strWhere, System.Data.CommandType.Text, null) > 0 ? true : false; } return false; }
这里有个标点的问题,因为是循环加入列的,列与列之间有逗号","相隔,笔者之前看到很多程序员喜欢加完符号后,再循环结束截取字符串,笔者不建议这样的操作,虽然语法不难,但笔者并不喜欢.所以笔者使用了这样的方式,在语句前面加上符号,并第一次不加入.
其他的就是拼接字符串了
下面我们说说新增吧,这里有个先后顺序问题
先上代码吧
#region 新增 private bool Add() { StringBuilder sql = new StringBuilder(); sql.AppendLine("INSERT INTO [" + ti.TabelName + "]("); bool index = false; bool index2 = false; StringBuilder value = new StringBuilder(); foreach (PropertyInfo item in ti.TabelType.GetProperties()) { //获取特性,再次验证 bool again = false; object[] objs = item.GetCustomAttributes(typeof(BindFiledAttribute), false); foreach (BindFiledAttribute bfa in objs) { if (bfa.IsIdentity) again = true; if (bfa.IsIdentity) continue; if (index) sql.AppendLine(","); index = true; sql.AppendLine(" [" + bfa.StrName+"]"); } if (again) continue; if (index2) value.AppendLine(","); index2 = true; value.AppendLine("'" + item.GetValue(model, null) + "'"); } sql.AppendLine(") VALUES ("); sql.AppendLine("" + value.ToString()); sql.AppendLine(")"); return DBSqlServer.ExecuteSql(sql.ToString(), System.Data.CommandType.Text, null)>0; } #endregion
这里我们需要两个字符串,一个用于拼接字符串,还有一个就是拼接值.在拼接列名时,直接记录下插入值,这样就不用考虑顺序的问题了,ok,下面还有一个小细节的问题,这个想必心细的读者已经发现了,那就是插入列时,我们需要判断该列是否是自动增涨列,如果是,则过滤这次操作,直接进入下一次操作
T_T...说起来好简单啊,笔者可是花了两天时间才完成呢!!!T_T
不抱怨了,下面是查询了,这个不算难,直接上代码了
/// <summary> /// 普通查询 /// </summary> /// <param name="strWhere">条件</param> /// <returns></returns> private DataSet Select(string strWhere) { StringBuilder sql = new StringBuilder(); sql.AppendLine("SELECT "); bool fast = true; foreach (FileInfo fi in ti.Propretys) { if (!fast) sql.AppendLine(","); fast = false; sql.AppendLine("["+fi.StrName+"]"); } fast = true; sql.AppendLine(" FROM [" + ti.TabelName + "] "); if (!string.IsNullOrEmpty(strWhere)) { sql.AppendLine("WHERE " + strWhere); } return DBSqlServer.ExecuteDataRead(sql.ToString(), CommandType.Text, null); }
这里有条件查询,也可以查询所有,你们懂得,笔者还是担心那些问题,,呵呵
笔者主要是想说分页的问题,这个分页笔者并不是很喜欢,因为还不算完善,之后笔者会去完善这一块的东西,希望大家理解
/// <summary> /// 分页查询 /// </summary> /// <param name="index">当前页</param> /// <param name="size">每页数据量</param> /// <param name="strWhere">条件</param> /// <param name="order">排序字段</param> /// <param name="desc">是否倒序</param> /// <returns></returns> private DataSet Select(int? index, int? size, string strWhere, string order, bool desc) { StringBuilder sql = new StringBuilder(); if (size <= 0 || index < 0) throw new Exception("超出参数表示范围.参数不可以小于0"); sql.AppendLine("select top " + size + " "); bool fast = true; string key = ""; foreach (FileInfo fi in ti.Propretys) { if (!fast) sql.AppendLine(","); fast = false; sql.AppendLine(" ["+fi.StrName+"]"); if (fi.IsKey) key = fi.StrName; } sql.AppendLine(" FROM ["+ti.TabelName+"] WHERE ["+key+"] NOT IN("); sql.AppendLine("select top " + (size * (index - 1)) + " ["+key+"] FROM ["+ti.TabelName+"]"); if (!string.IsNullOrEmpty(strWhere)) sql.AppendLine(" WHERE "+strWhere); if(!string.IsNullOrEmpty(order)) sql.AppendLine(" ORDER BY [" + order + "] " + (desc ? "DESC" : "ASC")); sql.AppendLine(")"); return DBSqlServer.ExecuteDataRead(sql.ToString(), CommandType.Text, null); } #endregion
这里主要是通过两个top来完成分页的,笔者之所以说不完善,是因为,在数据量超大的时候,这个会很耗效率,这个具体的,笔者会改善,因为时间比较紧,所以望读者们理解
下面就是这个类的完整代码
public class DBManage<T> { public DataSet ds_model = null; T model; public DBManage(T t) { model = t; FlagTabel(t.GetType()); } private Type t = null; private string GetSql() { return string.Empty; } #region 数据库操作分支入口 private TabelInfo ti = null; private void FlagTabel(Type t) { this.t = t; DBSqlServer.CreateTable<Type>(t, ref ti); } #region 数据库公开类 /// <summary> /// 公开数据操作 /// </summary> /// <param name="txt">sql</param> /// <param name="cmdType">操作类型</param> /// <param name="paras">参数列</param> /// <returns></returns> public static int ExecuteSql(string txt, CommandType cmdType, params SqlParameter[] paras) { return DBSqlServer.ExecuteSql(txt, cmdType, paras); } /// <summary> /// 公开数据操作 /// </summary> /// <param name="txt">sql</param> /// <param name="cmdType">操作类型</param> /// <param name="paras">参数列</param> /// <returns></returns> public static DataSet ExecuteDataSet(string txt, CommandType cmdType, params SqlParameter[] paras) { return DBSqlServer.ExecuteDataRead(txt, cmdType, paras); } #endregion /// <summary> /// 操作类 /// </summary> /// <typeparam name="T">需要操作的类</typeparam> /// <param name="t">需要操作的实体类</param> /// <param name="type">操作类型</param> public bool ManageModel(ModelState type) { return ResultManage(type, null, null, null, null, false); } /// <summary> /// 操作类 /// </summary> /// <typeparam name="T">需要操作的类</typeparam> /// <param name="t">需要操作的实体类</param> /// <param name="type">操作类型</param> /// <param name="index">当前页(用于分页查询)</param> /// <param name="size">每页条数(用于分页查询)</param> public bool ManageModel(ModelState type, int index, int size) { return ResultManage(type, index, size, null, null, false); } /// <summary> /// 操作类 /// </summary> /// <typeparam name="T">需要操作的类</typeparam> /// <param name="t">需要操作的实体类</param> /// <param name="type">操作类型</param> /// <param name="obj">多条件</param> public bool ManageModel(ModelState type, object[] obj) { return ResultManage(type, null, null, null, null, false,obj); } /// <summary> /// 操作类 /// </summary> /// <typeparam name="T">需要操作的类</typeparam> /// <param name="t">需要操作的实体类</param> /// <param name="type">操作类型</param> /// <param name="strWhere">单个条件</param> public bool ManageModel(ModelState type, string strWhere) { return ResultManage(type, null, null, strWhere,null,false); } /// <summary> /// 操作类 /// </summary> /// <typeparam name="T">需要操作的类</typeparam> /// <param name="t">需要操作的实体类</param> /// <param name="type">操作类型</param> /// <param name="index">当前页(用于分页查询)</param> /// <param name="size">每页条数(用于分页查询)</param> public bool ManageModel(ModelState type, int index, int size, string strWhere, string order, bool desc) { return ResultManage(type, index, size, strWhere, order,desc); } #endregion #region 分支判断 private bool ResultManage(ModelState type, int? index, int? size, string strWhere,string order,bool desc, params object[] objs) { bool flag = false; switch (type) { case ModelState.Add: //添加数据 flag = Add(); break; case ModelState.Delete: //删除数据 flag = Delete(strWhere); break; case ModelState.Select: //查询数据 bool asce = false; if (index != null) ds_model=Select(index, size, strWhere, order, asce); else ds_model=Select(strWhere); flag = false; if (ds_model != null) if (ds_model.Tables.Count > 0) if (ds_model.Tables[0].Rows.Count > 0) flag = true; break; case ModelState.Update: //修改数据 flag = Edite(null); break; default: throw new Exception("当前类型不存在"); break; } return flag; } #endregion #region 数据库具体操作 #region 新增 private bool Add() { StringBuilder sql = new StringBuilder(); sql.AppendLine("INSERT INTO [" + ti.TabelName + "]("); bool index = false; bool index2 = false; StringBuilder value = new StringBuilder(); foreach (PropertyInfo item in ti.TabelType.GetProperties()) { //获取特性,再次验证 bool again = false; object[] objs = item.GetCustomAttributes(typeof(BindFiledAttribute), false); foreach (BindFiledAttribute bfa in objs) { if (bfa.IsIdentity) again = true; if (bfa.IsIdentity) continue; if (index) sql.AppendLine(","); index = true; sql.AppendLine(" [" + bfa.StrName+"]"); } if (again) continue; if (index2) value.AppendLine(","); index2 = true; value.AppendLine("'" + item.GetValue(model, null) + "'"); } sql.AppendLine(") VALUES ("); sql.AppendLine("" + value.ToString()); sql.AppendLine(")"); return DBSqlServer.ExecuteSql(sql.ToString(), System.Data.CommandType.Text, null)>0; } #endregion #region 删除 private bool Delete(string strWhere) { StringBuilder sql = new StringBuilder(); try { sql.AppendLine("DELETE [" + ti.TabelName + "] "); if (string.IsNullOrEmpty(strWhere)) { //条件为空 foreach (PropertyInfo item in ti.TabelType.GetProperties()) { //获取特性,再次验证 object[] objs = item.GetCustomAttributes(typeof(BindFiledAttribute), false); bool fast = true; foreach (BindFiledAttribute bfa in objs) { if (bfa.IsKey) { if (fast) { sql.AppendLine(" WHERE "); fast = false; } sql.AppendLine(" [" + bfa.StrName + "]='" + item.GetValue(model, null) + "'"); } } } return DBSqlServer.ExecuteSql(sql.ToString(), System.Data.CommandType.Text, null) > 0 ? true : false; } else { //按条件查询 sql.AppendLine(" WHERE " + strWhere); return DBSqlServer.ExecuteSql(sql.ToString(), System.Data.CommandType.Text, null) > 0 ? true : false; } } catch (Exception) { return false; } } #endregion #region 查询 /// <summary> /// 普通查询 /// </summary> /// <param name="strWhere">条件</param> /// <returns></returns> private DataSet Select(string strWhere) { StringBuilder sql = new StringBuilder(); sql.AppendLine("SELECT "); bool fast = true; foreach (FileInfo fi in ti.Propretys) { if (!fast) sql.AppendLine(","); fast = false; sql.AppendLine("["+fi.StrName+"]"); } fast = true; sql.AppendLine(" FROM [" + ti.TabelName + "] "); if (!string.IsNullOrEmpty(strWhere)) { sql.AppendLine("WHERE " + strWhere); } return DBSqlServer.ExecuteDataRead(sql.ToString(), CommandType.Text, null); } /// <summary> /// 分页查询 /// </summary> /// <param name="index">当前页</param> /// <param name="size">每页数据量</param> /// <param name="strWhere">条件</param> /// <param name="order">排序字段</param> /// <param name="desc">是否倒序</param> /// <returns></returns> private DataSet Select(int? index, int? size, string strWhere, string order, bool desc) { StringBuilder sql = new StringBuilder(); if (size <= 0 || index < 0) throw new Exception("超出参数表示范围.参数不可以小于0"); sql.AppendLine("select top " + size + " "); bool fast = true; string key = ""; foreach (FileInfo fi in ti.Propretys) { if (!fast) sql.AppendLine(","); fast = false; sql.AppendLine(" ["+fi.StrName+"]"); if (fi.IsKey) key = fi.StrName; } sql.AppendLine(" FROM ["+ti.TabelName+"] WHERE ["+key+"] NOT IN("); sql.AppendLine("select top " + (size * (index - 1)) + " ["+key+"] FROM ["+ti.TabelName+"]"); if (!string.IsNullOrEmpty(strWhere)) sql.AppendLine(" WHERE "+strWhere); if(!string.IsNullOrEmpty(order)) sql.AppendLine(" ORDER BY [" + order + "] " + (desc ? "DESC" : "ASC")); sql.AppendLine(")"); return DBSqlServer.ExecuteDataRead(sql.ToString(), CommandType.Text, null); } #endregion #region 修改 private bool Edite(string strWhere) { StringBuilder sql = new StringBuilder(); //修改数据,1.是否有自定义条件 if (string.IsNullOrEmpty(strWhere)) { //根据主键修改 sql.AppendLine("UPDATE [" + ti.TabelName + "] SET "); bool fast = true; foreach (PropertyInfo item in ti.TabelType.GetProperties()) { //获取特性,再次验证 object[] objs = item.GetCustomAttributes(typeof(BindFiledAttribute), false); foreach (BindFiledAttribute bfa in objs) { if (bfa.IsKey || bfa.IsIdentity) { strWhere += "["+bfa.StrName + "]='" + item.GetValue(model, null) + "'"; continue; } if (!fast) sql.AppendLine(","); fast = false; sql.AppendLine("[" + bfa.StrName + "]='" + item.GetValue(model, null) + "' "); } } return DBSqlServer.ExecuteSql(sql.ToString() + " where " + strWhere, System.Data.CommandType.Text, null) > 0 ? true : false; } return false; } #endregion #endregion } public enum ModelState { Add, Select, Delete, Update }
这里有两个数据库公开操作方法,是为了便于程序编写自己的sql和调用存储过程而预留下来的.枚举ModelState是用于标识操作状态而预留的.
这里可以下载源码和demo,大家也可以加我qq(1772282755).反馈意见,笔者是新手,还望多多指点 https://files.cnblogs.com/xufei/ORMAttriBute.rar