今天在這里寫一套簡單的框架,主要用於一些小型的項目,用於數據的增刪改查,通用分頁查詢等操作.所以功能並不強大,而且筆者也是新手,這里面也難免會有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).反饋意見,筆者是新手,還望多多指點 http://files.cnblogs.com/xufei/ORMAttriBute.rar