想一想畢業已經快一年了,也就是大約兩年之前,懷着滿腔的熱血正式跨入程序員的世界,那時候的本身想象着所熱愛的技術生涯會是多麼的豐富多彩,天天能夠與大佬們坐在一塊兒討論解決各類牛逼的技術問題,喝着咖啡,翹着二郎腿,大體就是下面這幅場景:html
但是現實卻老是那麼不盡如人意,現實的所謂技術生涯是永遠寫不完的增刪改查,還有那日漸稀薄的頭髮,哎,難...git
話說回來,若是連增刪改查都作很差,還談何技術生涯。程序員
因此,我一直認爲:若是你認爲本身是一個優秀的程序員,那就應該從最基礎的增刪改查中就能體現出來。sql
有人可能會說,增刪改查?很難嗎?數據庫
其實,說難,也不難,無非就是寫SQL,Add、Delete、Update、Select,僅此而已;可是若是隻是從SQL的角度認爲這很容易,而對其不懈一顧,那你可能就和當初剛剛開始增刪改查大業的我同樣,太天真了。c#
首先,我和你們分享一下我在工做這將近兩年中在增刪改查這條路上的心路歷程。app
某年某月某日,大三尾聲,翹課在宿舍睡大覺的我剛從牀上艱難地爬起來,打開手機,發現剛工做的老學長阿威給我發來了一條信息:框架
"阿森,來活了,幫我搞個網站,會弄嗎?"編輯器
"網站?沒弄過誒。。"ide
"這個項目給的銀兩還挺多的。。"
"能夠,能夠,這個能夠搞,沒問題,阿威哥"
就這樣,我就走上了Web開發的道路。初入坑,首先遇到的問題就是數據庫的操做,可是通過本身的旁門左道的學習也大體摸清了使用ADO.NET操做數據庫的方法:
第一步,使用DBConnection創建與數據庫之間的鏈接,打開鏈接
第二步,而後建立DBCommand對象,初始化你想要執行的SQL語句
第三步,調用DBCommand的方法,執行SQL語句
第四步,使用DataReader逐條讀取sql執行的結果,或者使用DataAdapter類將結果填充(Fill)到DataSet中,最後關閉Connection鏈接
到此爲止,就實現了在.net中操做數據庫執行sql語句返回執行結果的操做。
固然,我以爲任何一個初級的程序員也都會給本身封裝一個叫作SQLHelper的幫助類,我也不例外,它能夠幫助你節省頻繁的創建數據庫鏈接(DBConnection)、初始化DBCommand對象、讀取sql執行結果等重複的代碼量。因此,封裝一個本身的SQLHelper工具類是一個初級程序員必備的素質。
我把一個當初本身封裝的SQLHelper類貼出來獻獻醜:
1 public static class SqlServerHelper 2 { 3 //數據庫鏈接字符串,從配置文件的配置字段中讀取 4 private static readonly string connStr = ConfigurationManager.ConnectionStrings["connStr"].ConnectionString; 5 6 /// <summary> 7 /// 建立新的數據庫鏈接 8 /// </summary> 9 public static SqlConnection CreateSqlConnection() 10 { 11 SqlConnection conn = new SqlConnection(connStr); 12 13 conn.Open(); //打開數據庫鏈接 14 15 return conn; 16 } 17 18 /// <summary> 19 /// 執行無結果返回的sql語句(共用同一個鏈接) 20 /// </summary> 21 /// <param name="sqlConn"></param> 22 /// <param name="sqlStr"></param> 23 /// <param name="sqlParamters"></param> 24 /// <returns>返回受影響的數據總條數</returns> 25 public static long ExecuteNoQuery(SqlConnection sqlConn, string sqlStr, params SqlParameter[] sqlParamters) 26 { 27 using (SqlCommand cmd = sqlConn.CreateCommand()) 28 { 29 cmd.CommandText = sqlStr; 30 cmd.Parameters.AddRange(sqlParamters); 31 32 long sum = cmd.ExecuteNonQuery(); 33 34 return sum; 35 } 36 } 37 38 /// <summary> 39 /// 執行無結果返回的sql語句(不共用一個鏈接) 40 /// </summary> 41 /// <param name="sqlStr"></param> 42 /// <param name="sqlParamters"></param> 43 /// <returns>返回受影響的數據總條數</returns> 44 public static long ExecuteNoQuery(string sqlStr, params SqlParameter[] sqlParamters) 45 { 46 using (SqlConnection sqlConn = CreateSqlConnection()) 47 using (SqlCommand cmd = sqlConn.CreateCommand()) 48 { 49 cmd.CommandText = sqlStr; 50 cmd.Parameters.AddRange(sqlParamters); 51 52 long sum = cmd.ExecuteNonQuery(); 53 54 return sum; 55 } 56 } 57 58 /// <summary> 59 /// 執行只有一行一列返回數據的sql語句(共用同一個鏈接) 60 /// </summary> 61 /// <param name="sqlConn"></param> 62 /// <param name="sqlStr"></param> 63 /// <param name="sqlParamters"></param> 64 /// <returns>返回結果的第一行第一列數據</returns> 65 public static object ExecuteScalar(SqlConnection sqlConn, string sqlStr, params SqlParameter[] sqlParamters) 66 { 67 using (SqlCommand cmd = sqlConn.CreateCommand()) 68 { 69 cmd.CommandText = sqlStr; 70 cmd.Parameters.AddRange(sqlParamters); 71 72 object res = cmd.ExecuteScalar(); 73 74 return res; 75 } 76 } 77 78 /// <summary> 79 /// 執行只有一行一列返回數據的sql語句(不共用同一個鏈接) 80 /// </summary> 81 /// <param name="sqlStr"></param> 82 /// <param name="sqlParamters"></param> 83 /// <returns>返回結果的第一行第一列數據</returns> 84 public static object ExecuteScalar(string sqlStr, params SqlParameter[] sqlParamters) 85 { 86 using (SqlConnection sqlConn = CreateSqlConnection()) 87 using (SqlCommand cmd = sqlConn.CreateCommand()) 88 { 89 cmd.CommandText = sqlStr; 90 cmd.Parameters.AddRange(sqlParamters); 91 92 object res = cmd.ExecuteScalar(); 93 94 return res; 95 } 96 } 97 98 /// <summary> 99 /// 執行有查詢結果的sql語句(共用同一個鏈接) 100 /// </summary> 101 /// <param name="sqlConn"></param> 102 /// <param name="sqlStr"></param> 103 /// <param name="sqlParamters"></param> 104 /// <returns></returns> 105 public static DataTable ExcuteQuery(SqlConnection sqlConn, string sqlStr, params SqlParameter[] sqlParamters) 106 { 107 using (SqlCommand cmd = sqlConn.CreateCommand()) 108 { 109 cmd.CommandText = sqlStr; 110 111 cmd.Parameters.AddRange(sqlParamters); 112 113 //把sql語句的執行結果填充到SqlDataAdapter中 114 SqlDataAdapter adapter = new SqlDataAdapter(cmd); 115 116 DataTable dt = new DataTable(); 117 adapter.Fill(dt); //將執行結果填充到dt對象中 118 119 return dt; 120 } 121 } 122 123 /// <summary> 124 /// 執行有查詢結果的sql語句(共用同一個鏈接) 125 /// </summary> 126 /// <param name="sqlStr"></param> 127 /// <param name="sqlParamters"></param> 128 /// <returns></returns> 129 public static DataTable ExcuteQuery(string sqlStr, params SqlParameter[] sqlParamters) 130 { 131 using (SqlConnection sqlConn = CreateSqlConnection()) 132 using (SqlCommand cmd = sqlConn.CreateCommand()) 133 { 134 cmd.CommandText = sqlStr; 135 136 cmd.Parameters.AddRange(sqlParamters); 137 138 //把sql語句的執行結果填充到SqlDataAdapter中 139 SqlDataAdapter adapter = new SqlDataAdapter(cmd); 140 141 DataTable dt = new DataTable(); 142 adapter.Fill(dt); //將執行結果填充到dt對象中 143 144 return dt; 145 } 146 } 147 148 /// <summary> 149 /// 批量插入數據到數據庫 150 /// </summary> 151 /// <param name="insertTable"></param> 152 /// <param name="dataTableName"></param> 153 public static void BatchInsert(DataTable insertTable, string dataTableName) 154 { 155 using (SqlBulkCopy sbc = new SqlBulkCopy(connStr)) 156 { 157 sbc.DestinationTableName = dataTableName; 158 159 for (int i = 0; i < insertTable.Columns.Count; i++ ) 160 { 161 sbc.ColumnMappings.Add(insertTable.Columns[i].ColumnName, insertTable.Columns[i].ColumnName); 162 } 163 164 sbc.WriteToServer(insertTable); 165 } 166 } 167 168 }
因而在那段開發的歲月裏,是這個SQLHelper類陪我走完了全程,向它說聲辛苦了...
大三暑假,因爲抑制不住想要出去試一試的衝動,我來到了一家小型互聯網公司實習,公司也是用.net開發網站的技術棧。
當上崗的第一天,我準備掏出我自認爲牛逼的SQLHelper的時候,卻被項目經理叫停了,項目經理阿勇對我說:
「小夥子,21世紀了,還在傻傻地用SQLHelper?來,試試EF吧,讓你欲罷不能...」
因而,一臉懵逼的我,一頭埋進了EF的世界中,不得不說,的確香。
EF全名EntityFramework,是微軟官方的一款ORM框架,支持Object(對象)與數據庫之間的數據映射,支持Linq的操做語法,受廣大.NET程序員青睞。
其實在接觸EntityFramework以前我就使用過Dapper,Dapper相對與EF來講是輕量的多的一款ORM框架,近乎於原生sql的寫法,讓它處於性能之最,也提供對象與數據庫表之間的映射。
但正是因爲用過了EF,我才知道了原來還有 Lambda to SQL 這種東西,相信大多數程序員都和我同樣經歷過寫原生SQL的痛苦:
不管是多麼簡單的一條sql,你都要在表設計文檔和sql編輯器中反覆切換比對字段,生怕本身打錯一個字母;並且咱們在基礎的業務中的大部分增刪改查其實都是至關簡單的單表操做sql,正是使用了Lambda to SQL 的代碼編寫方式,你能夠在VsStudio豐富的代碼提示下飛快地完成一條簡單的SQL語句。
爲何說簡單的SQL編寫才使用Lambda表達式的形式去編寫呢,複雜的sql就不行了嗎?
理由是,你要明白不論是Lambda仍是Linq的語句,最終都是在EF的SQL語句解析器中被翻譯成可供數據庫執行的sql語句,不得不說EF的Linq To SQL 的解析器的確強大,可是畢竟仍是機器翻譯的sql,當你讓它給你轉化一個複雜的linq語句時,它是必定考慮不到sql性能的優化。
就像你去用金山詞霸翻譯一個單詞,它能夠給你翻譯的很準確;可是你讓它去幫你翻譯一個長句,可能你讀着就以爲彆扭了;更有甚者把一篇論文粘貼複製到金山詞霸裏,那可能比你直接看英文原文還費勁,這是一樣一個道理,有些東西仍是須要人工來作,就好比優化sql語句。不能奢求什麼都扔給Lambda和Linq,它幫咱們作的已經足夠多了。
總之一句話,Lambda很香,但絕對不能替代SQL。
畢業後的我來到了一家大型製造業企業從事IT行業,說的這麼體面,其實仍是一個苦逼敲代碼的。
上崗的第一天我就問旁邊的程序媛,對,你沒看錯,是「媛」,不是「猿」,嘿嘿。想我代碼生涯一年以來,第一次見這麼多程序媛,低調低調,不要聲張,否則讓隔壁的程序猿聽到了會嫉妒的。
「姐姐,咱們這用EF嗎?」
「EF?是啥...」,姐姐一臉懵逼。。。
「那大家用什麼操做數據庫啊?本身封裝SQLHelper嗎?」
「用存儲過程啊,都用了七、8年了」
「哦,這樣啊」,我心想,都用了七、8年了,這個姐姐是個狠人。
入鄉隨俗,咱也不能壞了規矩,那就照着用吧,存儲過程之前用過幾回,可是那是在sql的邏輯比較複雜的時候纔會寫存儲過程調用的,要是全部的sql都放在存儲過程裏面去調用的話,那就太繁瑣了吧。
通過一段時間的使用,證實個人顧慮是對的。
所有使用存儲過程後,發現,就是一條簡單的Delete、Insert語句都要寫在存儲過程當中,簡直不要太麻煩。
首先的問題就是,很差編寫,對於一個剛上手存儲過程語法的程序員來講這簡直就是災難,目前的SQL編輯器沒有語法提示功能而形成很是很差的代碼編寫體驗,嚴重拖慢開發進程;
更要命的是,太難調試!當你在c#代碼中調用完存儲過程後,你發現程序安然無恙地執行完,可是並無獲得你想要的結果,因而你找啊找,找啊找,最後,你只能懷疑是否是存儲過程有問題,可是運行過程當中存儲過程一點動靜也沒有啊,這就是使用存儲過程最大的弊端,悄無聲息地出錯,徹底不知道里面發生了什麼,只能默默地把存儲過程的參數記下,而後輸入到sql的調試其中執行一遍才能夠發現錯誤。
而後你的項目經理跑過來問你昨天的代碼敲完了嗎,心累...
因而,我對存儲過程留下了很是很差的印象。可是存儲過程的好處是顯而易見的:當你的業務邏輯用一條sql解決不了的時候你會考慮使用多條sql來配合完成查詢,但是若是執行每一條sql語句都要與數據庫創建鏈接而後再執行的話好像有點繁瑣不說,主要是重建數據庫鏈接的過程也是須要時間與資源的,因此這個時候存儲過程就派上用場了,把你的sql都扔到存儲過程裏面去吧,多麼使人心曠神怡的操做,這個時候你就不要去想存儲過程出錯難找的問題了,由於你想要得到方便總要有點犧牲精神。
想要有Dapper的神速,又想要有EF中使用lambda表達式的便捷,可是兩者好像並不能兼得。
Dapper雖然是效率之王,可是它沒有EF中可使用的便捷的lambda表達式;
EF雖然可使用便捷的lambda、linq語法,但是因爲EF的過度強大(EF還具備對象追蹤的功能),讓它顯得稍微有點臃腫,屬於重量級的ORM框架。
因而我就在想,有沒有一款輕量級的ORM,既有不低的執行效率,又有簡單實用的Lambda TO SQL?
答案固然是,有的,如今開源的國產sqlSuger、freeSql,比比皆是。可是,我就是想本身試試造輪子的感受,目的並非說造出多麼好的ORM框架去超越他們,而是在這個過程當中學到的東西和獲得的歷練是很是可觀的。
沒辦法,有觀衆說「褲子都脫了,就給我看這個?」,我決定仍是先把藏的貨先擺出來,也好有個交代...
源碼地址:https://gitee.com/xiaosen123/CoffeeSqlORM
本文爲做者原創,轉載請註明出處:http://www.javashuo.com/article/p-kjpvnttp-dv.html