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         }
View Code

_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         }
View Code

_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         }
View Code

怎么樣,是不是很輕松呢,好,我們繼續向下說

特性已經出現了,那么我們必定需要有一個地方來存儲我們所標識的實體對應的值,所以筆者在這定義了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; }
        }
View Code
  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("沒有找到您想要刪除的數據集"); 
        }
    }
View Code

_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();
            }
        }
View Code

這里主要是讓他起到自動緩存和讀取的作用,不至於我們忘記緩存等操作而增加操作

好,現在我們的第一步工作算是完成了,我們進入第二步工作,數據庫的連接和數據庫操作等

這里我們可以重新創建類庫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
View Code

如此,我們便可以寫創建表和列的字符串了

    /// <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();
        }
View Code

這里,我們需要注意一點小細節

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);
        }
View Code

這里有這樣的一句話

 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;
        }
View Code

這里有個標點的問題,因為是循環加入列的,列與列之間有逗號","相隔,筆者之前看到很多程序員喜歡加完符號后,再循環結束截取字符串,筆者不建議這樣的操作,雖然語法不難,但筆者並不喜歡.所以筆者使用了這樣的方式,在語句前面加上符號,並第一次不加入.

其他的就是拼接字符串了

下面我們說說新增吧,這里有個先后順序問題

先上代碼吧

   #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
    }
View Code

這里有兩個數據庫公開操作方法,是為了便於程序編寫自己的sql和調用存儲過程而預留下來的.枚舉ModelState是用於標識操作狀態而預留的.

 這里可以下載源碼和demo,大家也可以加我qq(1772282755).反饋意見,筆者是新手,還望多多指點 http://files.cnblogs.com/xufei/ORMAttriBute.rar

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM