前面幾章主要是概念性的東西爲主,向初學者們介紹項目開始前的一些知識與內容,從本章開始將會進入實操階段,但願跟着本系統學習的朋友認真按說明作好每一步操做(對於代碼最好是直接照着文檔內容在你的IDE中打一次出來,而不是使用複製粘貼),這樣對你理解後面的章節會有較好的幫助,若是你對我這種書寫方式有什麼建議或支持,也但願在評論中留言,謝謝你的支持。html
SubSonic3.0簡介git
SubSonic是Rob Conery用c#語言寫的一 個ORM開源框架,使用BSD軟件受權許可(The BSD 3-Clause License)。它是一個實用的快速開發框架,經過很是簡單的配置,以及附帶的T4模板,就能夠幫咱們生成功能強大的數據訪問層工具,讓開發人員遠離SQL語句的拼接,專一於業務邏輯的開發。github
SubSonic3.0適合短、平、快的中小型項目開發,支持MsSql、MySql與SQLite三種數據庫,支持Linq和支持事務。對數據庫操做靈活,對生成的SQL語句會自動進行優化,雖然是ORM框架,但在性能上並無太大的損失。它上手容易,是一個很是棒的ORM開發框架。
sql
3.0版本最大的缺點是框架未開發完善,對多表關聯查詢支持的不是很好,只支持一個多表關聯條件(複雜的多表關聯只能使用存儲過程或SQL語句拼接方式來實現);條件語句對In與Not In不支持(須要在數據層從新封裝處理才行);若是使用Redis緩存的話,存儲數據時對subsonic3.0生成的實體有兼容問題,須要作一次轉換封裝後才能使用。數據庫
不過總的來講,這些缺點都是能夠克服的,在開發效率、二次開發、軟件維護上來講,優勢也是很是明顯的,請你們耐心學完本系列,你就能很容易的掌握SubSonic3.0這個開發利器。express
SubSonic3.0安裝說明c#
在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/