一個簡單的ORM制作大概需要以下幾個類:
- SQL執行類
- CURD操作類
- 其他醬油類
先從SQL執行類說起,可能會涉及數據庫的遷移等問題,所以需要定義一個接口以方便遷移到其他數據庫,
事務沒提供命名,若需要命名可修改為可變參數,IHelper代碼如下:
internal interface IHelper:IDisposable { int ExecuteQuery(string txt, IEnumerable<IDataParameter> ps, bool issp);//用於執行INSERT,UPDATE object ExectueScalar(string tex, IEnumerable<IDataParameter> ps, bool issp);//執行COUT() IDataReader ExectueReader(string tex, IEnumerable<IDataParameter> ps, bool issp);//執行SELECT void BegTran();//開始事務 void RollBack();//回滾 void Commit();//提交 string CreateSql(string select, string tbname, string where, string orderby, int size, int index);//數據庫的不同,產生的SQL也可能不同,所以必須提供不同的生成方案 IDataParameter Cp(string name, object value);//創建參數 string GetIdStr { get; }//獲取INSERT產生ID的SQL代碼,可能各個數據庫不太相同 string ParStr(string name);//參數標示符,比如MSSQL:@NAME, MYSQL:?NAME,ODBC直接返回?無命名 }
以上為我個人能思考到的數據庫差異和基礎功能,若有其他請大家指教
通用MsSql幫助類代碼如下:
class Mssql:IHelper { SqlCommand cmd; SqlConnection con; SqlTransaction tran; internal Mssql(string constr) { con = new SqlConnection(constr);//test cmd = new SqlCommand(); cmd.Connection = con; } void SetCmd(string str, IEnumerable<IDataParameter> ps, bool issp) { cmd.CommandText = str; cmd.CommandType = issp ? CommandType.StoredProcedure : CommandType.Text; cmd.Parameters.Clear(); foreach (var n in ps) { cmd.Parameters.Add(n); } } void CloseCon(){if (con.State == ConnectionState.Open) { con.Close(); }} void OpenCon() { if (con.State == ConnectionState.Closed) { con.Open(); } } int IHelper.ExecuteQuery(string str, IEnumerable<IDataParameter> ps, bool issp) { try { SetCmd(str, ps, issp); OpenCon(); return cmd.ExecuteNonQuery(); } finally{if(tran==null){CloseCon();}} } object IHelper.ExectueScalar(string str, IEnumerable<IDataParameter> ps, bool issp) { try { SetCmd(str, ps, issp); OpenCon(); return cmd.ExecuteScalar(); } finally{if(tran==null){CloseCon();}} } IDataReader IHelper.ExectueReader(string str, IEnumerable<IDataParameter> ps, bool issp) { SetCmd(str, ps, issp); OpenCon(); return cmd.ExecuteReader(tran==null?CommandBehavior.CloseConnection:CommandBehavior.Default); } void IHelper.BegTran() { OpenCon(); tran = con.BeginTransaction(); cmd.Transaction = tran; } void IHelper.Commit() { if (tran != null) { tran.Commit(); con.Close(); tran = null; } } void IHelper.RollBack() { if (tran != null) { tran.Rollback(); con.Close(); tran = null; } } string IHelper.CreateSql(string select, string tbname, string where, string orderby, int size, int index) { StringBuilder sb = new StringBuilder();//分頁需要排序 sb.Append("SELECT "); if (index == 1) { sb.Append("TOP " + size + " "); } sb.Append(select+" FROM "); if (index > 1){sb.Append("(SELECT ROW_NUMBER() OVER(" + (!string.IsNullOrEmpty(orderby)?"ORDER BY "+orderby:string.Empty) + ") AS ROWID," + select + " FROM ");} sb.Append(tbname); sb.Append(!string.IsNullOrEmpty(where) ? " WHERE " + where : string.Empty); if (index > 1) { sb.Append(") AS " + tbname + " WHERE ROWID BETWEEN " + ((index - 1) * size + 1) + " AND " + size * index); } else { sb.Append(!string.IsNullOrEmpty(orderby) ? " ORDER BY " + orderby : string.Empty); } return sb.ToString(); } IDataParameter IHelper.Cp(string name, object value) { return new SqlParameter(name, value); } string IHelper.ParStr(string name) { return "@"+name;} string IHelper.GetIdStr { get { return "SELECT @@IDENTITY"; } } void IDisposable.Dispose() { CloseCon(); con.Dispose(); cmd.Dispose(); } }
MsSql2005開始支持MARS,默認為關閉狀態,也可以重寫個支持MARS的Help,默認開啟2個連接,一個用於查詢一個用於無事物的執行,代碼如下:
class MsMars:IHelper//自動開啟mars,連接0為查詢連接,連接1為執行無事務連接,事務連接為新連接 { static SqlConnectionStringBuilder ssb; static SqlConnection[] globalCon; static object ck = new object(); public MsMars(string constr) { if (ssb == null) { ssb = new SqlConnectionStringBuilder(constr); ssb.MultipleActiveResultSets = true; } } static SqlCommand GetCmd(int i = 3) { if (ssb == null) { throw new Exception("連接未初始化..."); } if (i >=3
) { return new SqlConnection(ssb.ConnectionString).CreateCommand(); } if (globalCon != null) { return globalCon[i].CreateCommand(); } lock (ck) { if (globalCon != null) { return globalCon[i].CreateCommand(); } globalCon = new SqlConnection[2] { new SqlConnection(ssb.ConnectionString), new SqlConnection(ssb.ConnectionString) }; globalCon[0].Open(); globalCon[1].Open(); } return globalCon[i].CreateCommand(); } SqlCommand cmd; void SetCmd(string txt, IEnumerable<IDataParameter> ps, bool issp) { cmd.Parameters.Clear(); cmd.CommandText = txt; cmd.CommandType = issp ? CommandType.StoredProcedure : CommandType.Text; cmd.Parameters.AddRange(ps.ToArray()); } public int ExecuteQuery(string txt, IEnumerable<IDataParameter> ps, bool issp) { cmd = cmd ?? GetCmd(1); SetCmd(txt, ps, issp); return cmd.ExecuteNonQuery(); } public object ExectueScalar(string txt, IEnumerable<IDataParameter> ps, bool issp) { cmd = cmd ?? GetCmd(1); SetCmd(txt, ps, issp); return cmd.ExecuteScalar(); } public IDataReader ExectueReader(string txt, IEnumerable<IDataParameter> ps, bool issp) { cmd =cmd??GetCmd(0); SetCmd(txt, ps, issp); return cmd.ExecuteReader(); } public void BegTran() { cmd = GetCmd(); cmd.Transaction = cmd.Connection.BeginTransaction(); } public void RollBack() { cmd.Transaction.Rollback(); cmd.Connection.Close();cmd.Dispose(); } public void Commit() { cmd.Transaction.Commit(); cmd.Connection.Close(); cmd.Dispose(); } public string CreateSql(string select, string tbname, string where, string orderby, int size, int index)... public IDataParameter Cp(string name, object value)... public string GetIdStr...
public string ParStr(string name)... public void Dispose()...
以上代碼本人測試通過,Help類只是ORM的一個起步,曾經看過EF的代碼想學習下,但微軟的代碼實在是太高深(惡心),無從下手,所以我還是按照個人的做法來實現自己ORM,,下篇繼續講CURD操作類.讀過覺得還不錯請留下你的腳印,謝謝