在實際的.net mvc 項目中,會有多個類庫,生成不同的dll文件。
比如model類庫存放基本類,bussiness類庫存放業務操作,dao類庫存放數據庫去數操作,utils類庫存放工具類等。
為了方便,會將操作MySQL的過程單獨放在一個類庫中。只在這個類庫中引用MySQL提供的類庫-MySql.Data。
而其他的數據操作類庫需要操作數據庫的時候,只需要引用這個操作類就可以,不需要再引用-MySql.Data。防止在應用過程中版本不一致而導致項目運行失敗。
直接上代碼:
/// <summary> /// 數據庫操作類 /// </summary> public class MySqlOperation { public MySqlConnection conn; MySqlTransaction mySql_Tran; public MySqlOperation(string connStr) { conn = new MySqlConnection(connStr); } /// <summary> /// 打開服務器 /// </summary> public bool ConnOpen() { bool isOpen = false; try { if (conn.State != ConnectionState.Open) { conn.Open(); //isOpen = true; } if (conn.State == ConnectionState.Open) isOpen = true; } catch (Exception ex) { //LogTool.ExceptionLog(ex, "open database"); } return isOpen; } /// <summary> /// 關閉服務器 /// </summary> public void ConnClose() { if (conn.State != ConnectionState.Closed) conn.Close(); } /// <summary> /// 打開事務 /// </summary> /// <param name="cmd"></param> public void TranOpen(ref MySqlCommand cmd) { mySql_Tran = conn.BeginTransaction(); if (mySql_Tran != null) cmd.Transaction = mySql_Tran; } /// <summary> /// 關閉事務 /// </summary> /// <param name="as_Error"></param> public void TranClose(bool b) { if (mySql_Tran != null) { if (b) mySql_Tran.Commit(); else mySql_Tran.Rollback(); } } /// <summary> /// 獲取存儲過程cmd /// </summary> /// <param name="procName">存儲過程名</param> /// <returns></returns> private MySqlCommand GetProcCommand(string procName, MySqlParameter[] paraList) { MySqlCommand cmd = new MySqlCommand(); cmd.CommandText = procName; cmd.CommandType = CommandType.StoredProcedure; if (paraList != null) { foreach (MySqlParameter para in paraList) cmd.Parameters.Add(para); } cmd.Connection = conn; return cmd; } public MySqlCommand GetTextCommand(string sql) { MySqlCommand cmd = new MySqlCommand(); cmd.CommandText = sql; cmd.CommandType = CommandType.Text; cmd.Connection = conn; return cmd; } public MySqlDataReader GetDataReader(string sql, CommandBehavior comBehavior = CommandBehavior.CloseConnection, bool isTran = false) { MySqlDataReader dr = null; try { if (!ConnOpen()) return null; MySqlCommand cmd = GetTextCommand(sql); dr = cmd.ExecuteReader(comBehavior); } catch (Exception ex) { //LogTool.ExceptionLog(ex, "get datareader", sql); if (isTran) TranClose(false); if (conn.State == ConnectionState.Open) { ConnClose(); } } return dr; } public MySqlCommand Cmd_Proc(string procName, MySqlParameter[] paraList, bool isTran = true) { MySqlCommand cmd = null; try { if (!ConnOpen()) return null; cmd = GetProcCommand(procName, paraList); if (isTran) TranOpen(ref cmd); cmd.ExecuteNonQuery(); if (isTran) TranClose(true); ConnClose(); } catch (Exception ex) { cmd = null; //LogTool.ExceptionLog(ex, "exec proc:" + procName); if (isTran) TranClose(false); if (conn.State == ConnectionState.Open) { ConnClose(); } } finally { ConnClose(); } return cmd; } public DataSet GetDataSet(string sql, bool isTran = false) { DataSet ds = null; try { if (!ConnOpen()) return null; MySqlCommand cmd = GetTextCommand(sql); if (isTran) TranOpen(ref cmd); ds = new DataSet(); MySqlDataAdapter da = new MySqlDataAdapter(cmd); da.Fill(ds); if (isTran) TranClose(true); } catch (Exception ex) { //LogTool.ExceptionLog(ex, "get datatable:" + sql); if (isTran) TranClose(false); } finally { ConnClose(); } return ds; } public int ExecSQL(string sql, bool isTran = true, int cmdTimeoutSec = 0) { int res = -1; try { ConnOpen(); MySqlCommand cmd = GetTextCommand(sql); if (isTran) TranOpen(ref cmd); res = cmd.ExecuteNonQuery(); if (isTran) TranClose(true); } catch (Exception ex) { //LogTool.SqlLog(sql); //LogTool.ExceptionLog(ex, "Exce sql:" + sql); if (isTran) TranClose(false); } finally { ConnClose(); } return res; } public DataTable GetDataTable(string sql, bool isTran = false) { DataTable dt = null; try { ConnOpen(); MySqlCommand cmd = GetTextCommand(sql); if (isTran) TranOpen(ref cmd); dt = new DataTable(); MySqlDataAdapter da = new MySqlDataAdapter(cmd); da.Fill(dt); if (isTran) TranClose(true); } catch (Exception ex) { //LogTool.ExceptionLog(ex, "get datatable:" + sql); if (isTran) TranClose(false); } finally { ConnClose(); } return dt; } /// <summary> /// 單條查詢結果轉換成類 /// </summary> /// <param name="conStr">數據庫連接串</param> /// <param name="sql">數據庫操作語句</param> /// <returns></returns> public T getClass<T>(string sql) where T : class,new() { T tClass = null; try { MySqlDataReader reader = GetDataReader(sql); if (reader != null) { tClass = DataReaderUtils.DataReaderToClass<T>(reader); } reader.Close(); } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { ConnClose(); } return tClass; } /// <summary> /// 多條結果轉化為List列表 /// </summary> /// <param name="conStr"></param> /// <param name="sql"></param> /// <returns></returns> public List<T> getClassList<T>(string sql) where T : class, new() { List<T> tClassList = null; try { MySqlDataReader reader = GetDataReader(sql); if (reader != null) { tClassList = DataReaderUtils.DataReadertoList<T>(reader); } reader.Close(); } catch (Exception ex) { Console.WriteLine(ex.Message); } finally { ConnClose(); } return tClassList; } }
以上這個類刪除getClass()和getClassList()方法,完全可以直接拿來用,也不用做其他操作。select語句操作結果,用datatable表處理。update,insert,delete語句,直接用ExecSQL()方法處理。
但是,用datatable來對數據進行處理,總覺的很不方便。如果能直接返回到類或者List,你這樣的話就對數據進行操作就方便了許多。
所以,我們要結合Attribute和反射對取出來的數據進行處理,MySQL取出來的數據都是放在MySqlDataReader這個類里。
思路是
1. 對拿類里的屬性上的特性對數據庫取出來的數據列頭名進行比對,
2. 屬性的類型對數據類型進行比對。
3. 滿足的話,將數據賦值到屬性的value中。不滿足跳過,進行下一個比對,直至結束。
但是類又不固定,各個類里的屬性,成員,方法又不一樣,所以,我們還要使用泛型。由於只是select語句操作會使用到泛型。所以,我將這兩個情況單獨提出來放到其他的一個工具類里。
首先,利用特性取class數據或list數據
/// <summary> /// Datareader反射使用 標記 /// 標記 屬性在Datareader 中的字段名 以便反射賦值 /// </summary> [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field)] public class DataReaderModelAttribute : Attribute { private string datareaderfieldname; public string Datareaderfieldname { get { return this.datareaderfieldname; } } public DataReaderModelAttribute(string datareaderfielname) { this.datareaderfieldname = datareaderfielname; } }
這個特性是用在類上的屬性上,用法如下
其中,紅框和藍框的值不一定一致,但紅框里的值一定要和數據庫里對應的字段值保持一致。
接下來,將MySqlDataReader里數據循環放到類里。
/// <summary> /// dataReader轉換工具 /// </summary> public class DataReaderUtils { /// <summary> /// 放到最后 轉換 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="DataReader"></param> /// <returns></returns> public static List<T> DataReadertoList<T>(MySqlDataReader DataReader) where T : new() { List<T> t_lis = new List<T>(); if (DataReader != null) { if (!DataReader.IsClosed) {//暫未關閉 while (DataReader.Read()) { List<string> DataReaderColumnNames = ColumnNames(DataReader); T t = new T(); Type type = t.GetType(); PropertyInfo[] p_list = type.GetProperties(); FieldInfo[] fieldInfos = type.GetFields(); if (p_list != null && p_list.Length > 0) { foreach (var i in p_list) { Attribute datareaderattr = i.GetCustomAttribute(typeof(DataReaderModelAttribute), false); if (datareaderattr != null) { DataReaderModelAttribute dataattr = (DataReaderModelAttribute)datareaderattr; DataReader.GetSchemaTable().DefaultView.RowFilter = "ColumnName= '" + dataattr.Datareaderfieldname + "'"; if (!DataReaderColumnNames.Contains(dataattr.Datareaderfieldname)) { continue; } if (DataReader[dataattr.Datareaderfieldname].Equals(DBNull.Value)) {//如果是dbnull continue; } if (DataReader[dataattr.Datareaderfieldname].GetType().Name == "Int32") { int vals = Convert.ToInt32(DataReader[dataattr.Datareaderfieldname]); i.SetValue(t, vals, null); } if (DataReader[dataattr.Datareaderfieldname].GetType().Name == "Int64") { int vals = Convert.ToInt32(DataReader[dataattr.Datareaderfieldname]); i.SetValue(t, vals, null); } else { i.SetValue(t, DataReader[dataattr.Datareaderfieldname], null); } } else { continue; } } t_lis.Add(t); } else { if (fieldInfos != null && fieldInfos.Length > 0) { foreach (var i in fieldInfos) { Attribute datareaderattr = i.GetCustomAttribute(typeof(DataReaderModelAttribute), false); if (datareaderattr != null) { DataReaderModelAttribute dataattr = (DataReaderModelAttribute)datareaderattr; DataReader.GetSchemaTable().DefaultView.RowFilter = "ColumnName= '" + dataattr.Datareaderfieldname + "'"; if (!DataReaderColumnNames.Contains(dataattr.Datareaderfieldname)) { continue; } if (DataReader[dataattr.Datareaderfieldname].Equals(DBNull.Value)) {//如果是dbnull continue; } if (DataReader[dataattr.Datareaderfieldname].GetType().Name == "Int32") { int vals = Convert.ToInt32(DataReader[dataattr.Datareaderfieldname]); i.SetValue(t, vals); } if (DataReader[dataattr.Datareaderfieldname].GetType().Name == "Int64") { int vals = Convert.ToInt32(DataReader[dataattr.Datareaderfieldname]); i.SetValue(t, vals); } else { i.SetValue(t, DataReader[dataattr.Datareaderfieldname]); } } else { continue; } } t_lis.Add(t); } //DataReader.Close(); //break; } } // DataReader.Close(); return t_lis; } else { //關閉 return t_lis; } } else { return t_lis; } } /// <summary> /// 獲取datareader 列字段名稱集合 /// </summary> /// <param name="pReader"></param> /// <returns></returns> private static List<string> ColumnNames(MySqlDataReader pReader) { List<string> Columnnames = new List<string>(); for (int i = 0; i < pReader.FieldCount; i++) { Columnnames.Add(pReader.GetName(i)); } return Columnnames; } /// <summary> /// datareader to class object datareader 轉成 一個對象 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> public static T DataReaderToClass<T>(MySqlDataReader datareader) where T : class, new() { T t = new T(); Type type = t.GetType(); if (datareader != null) { PropertyInfo[] infos = type.GetProperties(); FieldInfo[] fieldInfos = type.GetFields(); if (infos != null && infos.Length > 0) { if (datareader.Read()) { List<string> DataReaderColumnNames = ColumnNames(datareader); foreach (var i in infos) { Attribute attr = i.GetCustomAttribute(typeof(DataReaderModelAttribute)); if (attr != null) { DataReaderModelAttribute dataattr = (DataReaderModelAttribute)attr; if (!DataReaderColumnNames.Contains(dataattr.Datareaderfieldname)) { continue; } if (datareader[dataattr.Datareaderfieldname].Equals(DBNull.Value)) {//如果是dbnull continue; } if (!datareader[dataattr.Datareaderfieldname].Equals(DBNull.Value)) { i.SetValue(t, datareader[dataattr.Datareaderfieldname]); } else { continue; } } else { continue; } } return t; } else { return null; } } else { if (fieldInfos != null && fieldInfos.Length > 0) { if (datareader.Read()) { List<string> DataReaderColumnNames = ColumnNames(datareader); foreach (var i in fieldInfos) { Attribute attr = i.GetCustomAttribute(typeof(DataReaderModelAttribute)); if (attr != null) { DataReaderModelAttribute dataattr = (DataReaderModelAttribute)attr; if (!DataReaderColumnNames.Contains(dataattr.Datareaderfieldname)) { continue; } if (datareader[dataattr.Datareaderfieldname].Equals(DBNull.Value)) {//如果是dbnull continue; } if (!datareader[dataattr.Datareaderfieldname].Equals(DBNull.Value)) { i.SetValue(t, datareader[dataattr.Datareaderfieldname]); } else { continue; } } else { continue; } } return t; } else { return null; } } else { return null; } } } else { return null; } } }
然后,在MySqlOperation里的getClass()方法和getClassList()方法就可以直接用了。
使用方法如下:
先實例化MySqlOperation類,然后調用。
class PersonDao { string conStr = "server=localhost;port=3306;database=XXX;uid=root;password=root;Allow User Variables=True"; public List<Person> GetAllPersonList(int index = 1, int pageSize = 10) { index = (index - 1) * 10; string sql = $"SELECT * FROM t_appoint_user limit {index},{pageSize}"; MySqlOperation sqlOperation = new MySqlOperation(conStr); return sqlOperation.getClassList<Person>(sql); } public Person GetPersonById(string id) { string sql = $"SELECT * FROM t_appoint_user WHERE rID = '{id}'"; MySqlOperation sqlOperation = new MySqlOperation(conStr); return sqlOperation.getClass<Person>(sql); } }
注:打日志,加try-catch