前面幾章主要是概念性的東西為主,向初學者們介紹項目開始前的一些知識與內容,從本章開始將會進入實操階段,希望跟着本系統學習的朋友認真按說明做好每一步操作(對於代碼最好是直接照着文檔內容在你的IDE中打一次出來,而不是使用復制粘貼),這樣對你理解后面的章節會有較好的幫助,如果你對我這種書寫方式有什么建議或支持,也希望在評論中留言,謝謝你的支持。
SubSonic3.0簡介
SubSonic是Rob Conery用c#語言寫的一 個ORM開源框架,使用BSD軟件授權許可(The BSD 3-Clause License)。它是一個實用的快速開發框架,通過非常簡單的配置,以及附帶的T4模板,就可以幫我們生成功能強大的數據訪問層工具,讓開發人員遠離SQL語句的拼接,專注於業務邏輯的開發。
SubSonic3.0適合短、平、快的中小型項目開發,支持MsSql、MySql與SQLite三種數據庫,支持Linq和支持事務。對數據庫操作靈活,對生成的SQL語句會自動進行優化,雖然是ORM框架,但在性能上並沒有太大的損失。它上手容易,是一個非常棒的ORM開發框架。
3.0版本最大的缺點是框架未開發完善,對多表關聯查詢支持的不是很好,只支持一個多表關聯條件(復雜的多表關聯只能使用存儲過程或SQL語句拼接方式來實現);條件語句對In與Not In不支持(需要在數據層重新封裝處理才行);如果使用Redis緩存的話,存儲數據時對subsonic3.0生成的實體有兼容問題,需要做一次轉換封裝后才能使用。
不過總的來說,這些缺點都是可以克服的,在開發效率、二次開發、軟件維護上來說,優點也是非常明顯的,請大家耐心學完本系列,你就能很容易的掌握SubSonic3.0這個開發利器。
SubSonic3.0安裝說明
在MsSql中新建一個數據庫SubSonicTest,並設置好登陸帳號與密碼為SubSonicTest。
運行下載包里的“SQL語句.txt”文件里的語句,生成數據表、記錄與測試用的存儲過程。
創建一個空白解決方案
在解決方案中創建一個空Web應用程序項目
將SubSonic文件夾復制進項目文件夾中
刷新項目就可以看到隱藏的SubSonic文件夾
打開Web.config,添加數據庫鏈接字串

<connectionStrings>
<!-- 連接數據庫的字符串 -->
<add name="procom" connectionString="server=.;Initial Catalog=SubSonicTest;uid=SubSonicTest;pwd=SubSonicTest"/>
</connectionStrings>
將Dll和SubSonic.Core復制到解決方案中
添加SubSonic3.0項目(直接使用源碼項目,方便在使用時調試及修改)
添加SubSonic.Core項目和Castle.Core.dll引用(大神TerryLee的博客里有Castle 開發系列文章 有興趣的朋友可以進去學習一下)
將SubSonic包含進項目中
如果你的數據庫名稱、帳號和密碼設置同面前要求一樣的話,T4模板將會直接運行生成相關實體類,如果設置不一樣的,請按下面要求來進行設置
打開Settings.ttinclude配置文件
設置好以后,選擇全部T4模板文件,運行生成代碼
SubSonic3.0模板介紹說明
本文只介紹附件中SubSonic文件夾模板(MsSql),不適用官方發布的模板
文件名稱 | 說明 |
ActiveRecord.tt | 按數據表生成對應名稱的類實體(Model),以及支持lambda表達式的各種常用函數(包括增、改、查、刪、Exists等) |
Context.tt | 生成常用公共模版函數:Select、Insert、Avg、Count、Max、Min、Variance、StandardDeviation、Sum、Delete、GetQuery、Update等 |
CreateModel.tt | 新增模板(原SubSonic3.0沒有這個模板),主要功能是數據表生成對應名稱的類實體(Model),這是普通的類實體,不附任何多余的內容(函數),主要用於存儲到Redis緩存或做C/S接口通訊時轉Json使用。非必須項 |
EntityTable.tt | 新增模板(原SubSonic3.0沒有這個模板,里面的功能從Structs.tt模板中分離出來的),主要功能是可直接獲取數據表名稱與字段名稱,減少開發中硬編碼的存在 |
Settings.ttinclude | 模版參數配置 |
SQLServer.ttinclude | MsSql數據庫讀取、生成的相關配置 |
StoredProcedures.tt | 生成存儲過程調用函數(本模板生成的函數調用存儲過程非常方便,詳情請關注例子) |
Structs.tt | 生成表結構模版,提供給SubSonic插件調用 |
SubSonic3.0使用例子
之前發布過《SubSonic3.0使用例子》,當時剛開始接觸寫得有點亂,現在重新整理一下,使用上面生成的類來進行操作,可以在項目中直接運行。對於下面的例子,可以直接在解決方案中Debug運行,查看運行結果,以加深理解,當然大部分功能在正式開發中很少使用,所以簡單了解一下就可以了,只要會用Lambda,那么后面相關章節介紹時你就會使用。
下面例子只適用於本文所附帶的模板,特此說明

using System; using System.Collections.Generic; using System.Data; using System.Linq; using System.Text; using Solution.DataAccess.DataModel; using SubSonic.Linq.Structure; using SubSonic.Query; namespace SubSonicTest { public partial class Test : System.Web.UI.Page { protected void Page_Load(object sender, EventArgs e) { //------------------------------------------------------------------------------- // 新增記錄 //------------------------------------------------------------------------------- var branch = new Branch(); branch.DeptCode = SPs.P_Branch_GetMaxBranchCode(2, 1).ExecuteScalar() + ""; branch.Name = "客服部"; branch.Comment = "客戶售后服務維護部門"; branch.ParentId = 1; branch.Sort = 7; branch.Depth = 2; //AddDate這個屬性不用賦值,ORM框架生成更新語句時會自動過濾該字段,更新時將會使用數據庫中設置的默認值 //branch.AddDate = DateTime.Now; //保存進數據庫 branch.Save(); WriteLine("記錄添加成功,新增Id為:" + branch.Id); //------------------------------------------------------------------------------- // 修改記錄 //------------------------------------------------------------------------------- //從數據庫中讀出剛添加的記錄 var branchModel = Branch.SingleOrDefault(x => x.Id == branch.Id); //也可以用這個 //var branchModel = new Branch(x => x.Id == branch.Id); //打印讀取出來的數據 WriteLine(branchModel.ToString()); //修改名稱為“售后服務部” branchModel.Name = "售后服務部"; //保存進數據庫 branchModel.Save(); //重新從數據庫中讀取出來並打印到輸出窗口 WriteLine((new Branch(x => x.Id == branch.Id)).ToString()); //------------------------------------------------------------------------------- // 判斷剛剛修改的記錄是否存在 //------------------------------------------------------------------------------- if (Branch.Exists(x => x.Id == branch.Id)) { WriteLine("Id為" + branch.Id + "的記錄存在!"); } else { WriteLine("Id為" + branch.Id + "的記錄不存在!"); } //------------------------------------------------------------------------------- // 刪除記錄 //------------------------------------------------------------------------------- //刪除當前記錄 Branch.Delete(x => x.Id == branch.Id); //也可以使用這種方法刪除 //branchModel.Delete(); WriteLine("刪除Id為" + branch.Id + "的記錄成功!"); //除了上面兩種刪除方法外,還有好幾種其它方法,不過都不常用,這里就不詳細羅列出來,大家如果有興趣可以查看我之前發布的博客 //------------------------------------------------------------------------------- // 判斷剛剛刪除的記錄是否存在 //------------------------------------------------------------------------------- if (Branch.Exists(x => x.Id == branch.Id)) { WriteLine("Id為" + branch.Id + "的記錄存在!"); } else { WriteLine("Id為" + branch.Id + "的記錄不存在!"); } //------------------------------------------------------------------------------- // 使用類實體附帶的函數查詢 //------------------------------------------------------------------------------- //查找出所有記錄——使用All() var list = Branch.All(); foreach (var tem in list) { //打印到輸出窗口 WriteLine(tem.ToString()); } //查詢指定條件的記錄——使用Find() IList<Branch> il = Branch.Find(x => x.Id > 0); foreach (var tem in il) { //打印到輸出窗口 WriteLine(tem.ToString()); } //獲取第2頁記錄(每頁3條記錄) il = Branch.GetPaged("Id Desc", 2, 3); foreach (var tem in il) { //打印到輸出窗口 WriteLine(tem.ToString()); } //使用Id倒序排序,獲取第3頁記錄(每頁3條記錄) il = Branch.GetPaged("Id Desc", 3, 3); foreach (var tem in il) { //打印到輸出窗口 WriteLine(tem.ToString()); } //------------------------------------------------------------------------------- // 使用Select類查詢 //------------------------------------------------------------------------------- //創建Select對象 //var select = new Select(); //顯示指定的列 var select = new Select(new string[] { BranchTable.Id, BranchTable.Name, BranchTable.DeptCode }); //指定查詢表 select.From<Branch>(); //運行完上面這條語句后,SQL已經生成出來了,大家在Debug狀態將鼠標指向select就可以看到,往下繼續執行時,每添加一個屬性都會添加在生成的SQL語句中 //添加查詢條件——Id大於2且編號頭兩位為01的部門 select.Where(BranchTable.Id).IsGreaterThanOrEqualTo(2).And(BranchTable.DeptCode).StartsWith("01"); //查詢時括號添加例子 //select.Openexpression_r().Where("").IsEqualTo(0).Or("").IsEqualTo(11).Closeexpression_r().And("").IsEqualTo(3); //設置去重復——SubSonic沒有去重復選項,需要自己手動修改Dll源碼 select.Distinct(true); //或 //select.IsDistinct = true; //設置查詢數量 select.Top("5"); //添加排序——倒序 select.OrderDesc(BranchTable.Sort); //或 //List<string> orderbyList = new List<string>(); //orderbyList.Add(BranchTable.Sort + " Desc"); //orderbyList.Add(BranchTable.Id + " Desc"); //select.OrderBys = orderbyList; //設置分頁,獲取第一頁記錄(每頁10條記錄) select.Paged(1, 10); //執行查詢——返回DataTable var dt = select.ExecuteDataTable(); if (dt != null && dt.Rows.Count > 0) { for (int i = 0; i < dt.Rows.Count; i++) { //打印到輸出窗口 WriteLine(dt.Rows[i][BranchTable.Id] + " " + dt.Rows[i][BranchTable.Name]); } } //執行查詢——返回List var bl = select.ToList<Branch>(); foreach (var tem in bl) { //打印到輸出窗口 WriteLine(tem.ToString()); } //查詢總記錄數 var recordCount = select.GetRecordCount(); //打印到輸出窗口 WriteLine("記錄數量:" + recordCount.ToString()); //select提供了很多接口,可以返回很多不同的數據,具體大家可以根據需求來獲取 //Select與SqlQuery 主要用於條件等屬性不確定時拼接查詢,如果大家需要使用相關內容,可以留意后面的章節源碼,我已將相關的功能封裝到一些類中了,大家可以直接調用 //------------------------------------------------------------------------------- // HotelDBDB查詢類的使用方式 //------------------------------------------------------------------------------- //使用數據庫名稱+DB作為名稱的類,可以直接調用聚合函數 var db = new SubSonicTestDB(); //平均值 WriteLine("平均值:" + db.Avg<Branch>(x => x.Id).Where<Branch>(x => x.Id < 10).ExecuteScalar() + ""); //計算數量 WriteLine("計算數量:" + db.Count<Branch>(x => x.Id).ExecuteScalar() + ""); //計算合計數量 WriteLine("計算合計數量:" + db.Sum<Branch>(x => x.Id).ExecuteScalar() + ""); //最大值 WriteLine("最大值:" + db.Max<Branch>(x => x.Id).ExecuteScalar() + ""); //最小值 WriteLine("最小值:" + db.Min<Branch>(x => x.Id).ExecuteScalar() + ""); //------------------------------------------------------------------------------- // 存儲過程調用方法 //------------------------------------------------------------------------------- //使用SPs.存儲過程名稱(參數1, 參數2, 參數3);就可以調用存儲過程 var obj = SPs.P_Branch_GetMaxBranchCode(1, 0).ExecuteScalar(); WriteLine(obj + ""); //可根據存儲過程返回的數據,調用不同的Execute來獲取 //大家試試在SPs.P_Branch_GetMaxBranchCode(1, 2)后面.一下,就可以看到很多調用接口,使用對應的接口可以返回不同的內容 //------------------------------------------------------------------------------- // 直接執行QueryCommand的方式 //------------------------------------------------------------------------------- //獲取數據源——主要用於綁定連接的服務器,如果有多台服務器多個數據庫時,可使用不同的數據源來進行綁定查找 var provider = SubSonic.DataProviders.ProviderFactory.GetProvider(); //定義事務,給后面的事務調用 var batch = new BatchQuery(provider); var sql = string.Format("select * from {0}", BranchTable.TableName); //例一,獲取影響記錄數 QueryCommand qcommand = new QueryCommand(sql, provider); WriteLine(qcommand.Provider.ExecuteQuery(qcommand) + ""); //例二,獲取DataTable var q = new SubSonic.Query.QueryCommand(sql, provider); var table = q.Provider.ExecuteDataSet(q).Tables[0]; if (dt != null && table.Rows.Count > 0) { for (int i = 0; i < table.Rows.Count; i++) { //打印到輸出窗口 WriteLine(table.Rows[i][BranchTable.Id] + " " + table.Rows[i][BranchTable.Name]); } } //例三,使用事務執行 batch.QueueForTransaction(qcommand); batch.ExecuteTransaction(); //例四,直接使用數據源執行 provider.ExecuteQuery(qcommand); //------------------------------------------------------------------------------- //------------------------------------------------------------------------------- // Linq查詢方式 //------------------------------------------------------------------------------- //Linq查詢方式 var query = new Query<Branch>(db.Provider); var posts = from p in query where p.DeptCode.StartsWith("0101") select p; foreach (var tem in posts) { //打印到輸出窗口 WriteLine(tem.ToString()); } query = db.GetQuery<Branch>(); posts = from p in query where p.Id > 3 && p.Id < 6 select p; //獲取查詢結果1 foreach (var tem in posts) { //打印到輸出窗口 WriteLine(tem.ToString()); } //獲取查詢結果2 List<Branch> li2 = query.ToList<Branch>(); foreach (var tem in li2) { //打印到輸出窗口 WriteLine(tem.ToString()); } //------------------------------------------------------------------------------- // Linq多表關聯查詢方法 //------------------------------------------------------------------------------- //方法一 var query5 = from p in Position.All() join b in Branch.All() on p.Branch_Id equals b.Id where b.DeptCode == "0101" select p; foreach (var tem in query5) { //打印到輸出窗口 WriteLine(tem.ToString()); } //方法二 var qry = (from p in db.Position join b in db.Branch on p.Branch_Id equals b.Id where b.DeptCode == "0101" select new ListView { PositionName = p.Name, BranchName = p.Branch_Name, DeptCode = b.DeptCode }); foreach (var view in qry) { WriteLine(view.ToString()); } //------------------------------------------------------------------------------- // 使用事務 //------------------------------------------------------------------------------- //例一 //從部門表中查詢出編號為0102的Id、名稱與說明三列 var query1 = new SubSonic.Query.Select(provider, BranchTable.Id, BranchTable.Name, BranchTable.Comment).From(BranchTable.TableName).Where<Branch>(x => x.DeptCode == "0102"); //加入事務 batch.QueueForTransaction(query1); //查詢部門編號為0102且職位名稱后面兩個字為主管的所有職位 var query2 = new SubSonic.Query.Select(provider).From<Position>().Where<Position>(x => x.Branch_DeptCode == "0102").And(PositionTable.Name).EndsWith("主管"); //加入事務 batch.QueueForTransaction(query2); //運行事務,不返回任何信息 batch.ExecuteTransaction(); //例二 batch = new BatchQuery(); batch.Queue(query1); batch.Queue(query2); //執行事務,並返回數據 using (IDataReader rdr = batch.ExecuteReader()) { if (rdr.Read()) { //query1 results for (int i = 0; i < rdr.FieldCount; i++) { WriteLine(rdr[i] + ""); } } //rdr.MoveNext(); rdr.NextResult(); if (rdr.Read()) { //query2 results for (int i = 0; i < rdr.FieldCount; i++) { WriteLine(rdr[i] + ""); } } } //例三 batch = new BatchQuery(provider); var query3 = from p in db.Branch where p.Id > 1 && p.Id < 10 select p; batch.Queue(query3); var query4 = from p in db.Position where p.Branch_DeptCode == "0103" select p; batch.Queue(query4); //執行事務,並返回數據 using (var rdr = batch.ExecuteReader()) { if (rdr.Read()) { //query1 results for (int i = 0; i < rdr.FieldCount; i++) { WriteLine(rdr[i] + ""); } } //rdr.MoveNext(); rdr.NextResult(); if (rdr.Read()) { //query2 results for (int i = 0; i < rdr.FieldCount; i++) { WriteLine(rdr[i] + ""); } } } } /// <summary> /// DeBug時,在輸出窗口打印出指定內容 /// </summary> /// <param name="str">要在輸出窗口顯示的內容</param> private void WriteLine(string str) { System.Diagnostics.Debug.WriteLine(str); } //內部類 class ListView { public string PositionName { get; set; } public string BranchName { get; set; } public string DeptCode { get; set; } public string ToString() { StringBuilder sb = new StringBuilder(); sb.Append("PositionName = " + PositionName + "\r\n"); sb.Append("BranchName = " + BranchName + "\r\n"); sb.Append("DeptCode = " + DeptCode + "\r\n"); return sb.ToString(); } } } }
版權聲明:
本文由AllEmpty原創並發布於博客園,歡迎轉載,未經本人同意必須保留此段聲明,且在文章頁面明顯位置給出原文鏈接,否則保留追究法律責任的權利。如有問題,可以通過1654937@qq.com 聯系我,非常感謝。
發表本編內容,只要主為了和大家共同學習共同進步,有興趣的朋友可以加加Q群:327360708 或Email給我(1654937@qq.com),大家一起探討。
更多內容,敬請觀注博客:http://www.cnblogs.com/EmptyFS/